1. 程式人生 > >android sim 卡雙卡雙待

android sim 卡雙卡雙待

Android的RIL驅動模組,在hardware/ril目錄下,一共分rild,libril.so以及librefrence_ril.so三個部分,另有一 radiooptions可供自動或手動除錯使用。都依賴於include目錄中ril.h標頭檔案。目前cupcake分支上帶的是gsm的支援,另有一 cdma分支,這裡分析的是gsm驅動。

GSM模組,由於Modem的歷史原因,AP一直是通過基於串列埠的AT命令與BB互動。包括到了目前的一些edge或3g模組,或像omap這類ap,bp整合的晶片,已經使用了USB或其他等高速匯流排通訊,但大多仍然使用模擬串列埠機制來使用AT命令。這裡的RIL(Radio Interface Layer)層,主要也就是基於AT命令的操作,如發命令,response解析等。(gprs等傳輸會用到的MUX協議等在這裡並沒有包含,也暫不作介紹。)

  以下是詳細分析,本文主要涉及基本架構和初始化的內容:

  首先介紹一下rild與libril.so以及librefrence_ril.so的關係:

  1. rild:

  僅實現一main函式作為整個ril層的入口點,負責完成初始化。

  2. libril.so:

  與rild結合相當緊密,是其共享庫,編譯時就已經建立了這一關係。組成部分為ril.cpp,ril_event.cpp。libril.so駐留在 rild這一守護程序中,主要完成同上層通訊的工作,接受ril請求並傳遞給librefrence_ril.so,同時把來自librefrence_ril.so的反饋回傳給呼叫程序。

  3. librefrence_ril.so:

  rild通過手動的dlopen方式載入,結合稍微鬆散,這也是因為librefrence.so主要負責跟Modem硬體通訊的緣故。這樣做更方便替換或修改以適配更多的Modem種類。它轉換來自libril.so的請求為AT命令,同時監控Modem的反饋資訊,並傳遞迴libril.so。在初始化時, rild通過符號RIL_Init獲取一組函式指標並以此與之建立聯絡。

     4. radiooptions:

  radiooptiongs通過獲取啟動引數, 利用socket與rild通訊,可供除錯時配置Modem引數。

  接下來分析初始化流程,主入口是rild.c中的main函式,主要完成三個任務:

  1. 開啟libril.so中的event機制, 在RIL_startEventLoop中,是最核心的由多路I/O驅動的訊息迴圈。

  2. 初始化librefrence_ril.so,也就是跟硬體或模擬硬體modem通訊的部分(後面統一稱硬體), 通過RIL_Init函式完成。

  3. 通過RIL_Init獲取一組函式指標RIL_RadioFunctions, 並通過RIL_register完成註冊,並開啟接受上層命令的socket通道。

  首先看第一個任務,也就是RIL_startEventLoop函式。RIL_startEventLoop在ril.cpp中實現,它的主要目的是通過pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL)建立一個dispatch執行緒,入口點在eventLoop. 而eventLoop中,會調ril_event.cpp中的ril_event_loop()函式,建立起訊息(event)佇列機制。

  我們來仔細看看這一訊息佇列的機制,這些程式碼都在ril_event.cpp中。

  1. void ril_event_init();  
  2. void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param);  
  3. void ril_event_add(struct ril_event * ev);  
  4. void ril_timer_add(struct ril_event * ev, struct timeval * tv);  
  5. void ril_event_del(struct ril_event * ev);  
  6. void ril_event_loop();  
  7. struct ril_event {  
  8. struct ril_event *next;  
  9. struct ril_event *prev;  
  10. int fd;  
  11. int index;  
  12. bool persist;  
  13. struct timeval timeout;  
  14. ril_event_cb func;  
  15. void *param;  
  16. };  
 

  每個ril_event結構,與一個fd控制代碼繫結(可以是檔案,socket,管道等),並且帶一個func指標去執行指定的操作。

  具體流程是: ril_event_init完成後,通過ril_event_set來配置一新ril_event,並通過ril_event_add加入佇列之中(實際通常用rilEventAddWakeup來新增),add會把佇列裡所有ril_event的fd,放入一個fd集合readFds中。這樣 ril_event_loop能通過一個多路複用I/O的機制(select)來等待這些fd,如果任何一個fd有資料寫入,則進入分析流程processTimeouts(),processReadReadies(&rfds, n),firePending()。 後文會詳細分析這些流程。

  另外我們可以看到, 在進入ril_event_loop之前,已經掛入了一s_wakeupfd_event, 通過pipe的機制實現的,這個event的目的是可以在一些情況下,能內部喚醒ril_event_loop的多路複用阻塞,比如一些帶timeout的命令timeout到期的時候。

  至此第一個任務分析完畢,這樣便建立起了基於event佇列的訊息迴圈,稍後便可以接受上層發來的的請求了(上層請求的event物件建立,在第三個任務中)。

  接下來看第二個任務,這個任務的入口是RIL_Init, RIL_Init首先通過引數獲取硬體介面的裝置檔案或模擬硬體介面的socket. 接下來便新開一個執行緒繼續初始化, 即mainLoop。

  mainLoop的主要任務是建立起與硬體的通訊,然後通過read方法阻塞等待硬體的主動上報或響應。在註冊一些基礎回撥(timeout,readerclose)後,mainLoop首先開啟硬體裝置檔案,建立起與硬體的通訊,s_device_path和s_port 是前面獲取的裝置路徑引數,將其開啟(兩者可以同時開啟並擁有各自的reader,這裡也很容易新增雙卡雙待等支援)。

  接下來通過 at_open函式建立起這一裝置檔案上的reader等待迴圈,這也是通過新建一個執行緒完成, ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr),入口點readerLoop。

  AT命令都是以rn或nr的換行符來作為分隔符的,所以readerLoop是line驅動的,除非出錯,超時等,否則會讀到一行完整的響應或主動上報,才會返回。這個迴圈跑起來以後,我們基本的AT響應機制已經建立了起來。它的具體分析,包括at_open中掛接的ATUnsolHandler, 我們都放到後面分析response的連載文章裡去。

  有了響應的機制(當然,能與硬體通訊也已經可以發請求了),通過 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0),跑到initializeCallback中,執行一些Modem的初始化命令,主要都是AT命令的方式。發AT命令的流程,我們放到後面分析request的連載文章裡。這裡可以看到,主要是一些引數配置,以及網路狀態的檢查等。至此第二個任務分析完畢,硬體已經可以訪問了。

  最後是第三個任務。第三個任務是由RIL_Init的返回值開始的,這是一個RIL_RadioFunctions結構的指標。

  1. typedefstruct {  
  2. int version;        /* set to RIL_VERSION */
  3. RIL_RequestFunc onRequest;  
  4. RIL_RadioStateRequest onStateRequest;  
  5. RIL_Supports supports;  
  6. RIL_Cancel onCancel;  
  7. RIL_GetVersion getVersion;  
  8. } RIL_RadioFunctions;  
 

  其中最重要的是onRequest域,上層來的請求都由這個函式進行對映後轉換成對應的AT命令發給硬體。

  rild通過RIL_register註冊這一指標。

  RIL_register中要完成的另外一個任務,就是開啟前面提到的跟上層通訊的socket介面(s_fdListen是主介面,s_fdDebug供除錯時使用)。

  然後將這兩個socket介面使用任務一中實現的機制進行註冊(僅列出s_fdListen)

  1. ril_event_set (&s_listen_event, s_fdListen, false,  
  2. listenCallback, NULL);  
  3. rilEventAddWakeup (&s_listen_event);  
 

  這樣將兩個socket加到任務一中建立起來多路複用I/O的檢查控制代碼集合中,一旦有上層來的(除錯)請求,event機制便能響應處理了。到這裡啟動流程已經分析完畢。

request流程

1. 多路複用I/O機制的運轉
上文說到request是接收,是通過ril_event_loop中的多路複用I/O,也對初始化做了分析.現在我們來仔細看看這個機制如何運轉.
ril_event_set負責配置一個event,主要有兩種event:
ril_event_add新增使用多路I/O的event,它負責將其掛到佇列,同時將event的通道控制代碼fd加入到watch_table,然後通過select等待.
ril_timer_add新增timer event,它將其掛在佇列,同時重新計算最短超時時間.
無論哪種add,最後都會呼叫triggerEvLoop來重新整理佇列,更新超時值或等待物件.
重新整理之後, ril_event_loop從阻塞的位置,select返回,只有兩種可能,一是超時,二是等待到了某I/O操作.
超時的處理在processTimeouts中,摘下超時的event,加入pending_list.
檢查有I/O操作的通道的處理在processReadReadies中,將超時的event加入pending_list.
最後在firePending中,檢索pending_list的event並依次執行event->func.
這些操作完之後,計算新超時時間,並重新select阻塞於多路I/O.
前面的初始化流程已分析得知,初始化完成以後,佇列上掛了3個event物件,分別是:
s_listen_event: 名為rild的socket,主要requeset & response通道
s_debug_event: 名為rild-debug的socket,除錯用requeset & response通道(流程與s_listen_event基本相同,後面僅分析s_listen_event)
s_wakeupfd_event: 無名管道,用於佇列主動喚醒(前面提到的佇列重新整理,就用它來實現,請參考使用它的相關地方)
2. request的傳入和dispatch
明白了event佇列的基本執行流程,我們可以來看看request是怎麼傳入和dispatch的了.
上層的部分,核心程式碼在frameworks/base/telephony/java/com/android/internal/telephony /gsm/RIL.java,這是android java框架處理radio(gsm)的核心元件.本文因為主要關注rild,也就是驅動部分,所以這裡只作簡單介紹.
我們看一個具體的例子,RIL.java中的dial函式:
    

  1. publicvoid
  2.     dial (String address, int clirMode, Message result)  
  3.     {  
  4.         RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);  
  5.         rr.mp.writeString(address);  
  6.         rr.mp.writeInt(clirMode);  
  7.         if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));  
  8.         send(rr);  
  9.     }  

rr是以RIL_REQUEST_DIAL為request號而申請的一個RILRequest物件.這個request號在java框架和rild庫中共享(參考RILConstants.java中這些值的由來:))
RILRequest初始化的時候,會連線名為rild的socket(也就是rild中s_listen_event繫結的socket),初始化資料傳輸的通道. 
rr.mp 是Parcel物件,Parcel是一套簡單的序列化協議,用於將物件(或物件的成員)序列化成位元組流,以供傳遞引數之用.這裡可以看到String address和int clirMode都是將依次序列化的成員.在這之前,rr初始化的時候,request號跟request的序列號(自動生成的遞增數),已經成為頭兩個將被序列化的成員.這為後面的request解析打下了基礎.
接下來是send到handleMessage的流程,send將rr直接傳遞給另一個執行緒的handleMessage,handleMessage執行data = rr.mp.marshall()執行序列化操作, 並將data位元組流寫入到rild socket.
接下來回到我們的rild,select發現rild socket有了請求連結的訊號,導致s_listen_event被掛入pending_list,執行event->func,即
static void listenCallback (int fd, short flags, void *param);
接下來,s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen),獲取傳入的socket描述符,也就是上層的java RIL傳入的連線.
然後,通過record_stream_new建立起一個record_stream, 將其與s_fdCommand繫結, 這裡我們不關注record_stream 的具體流程, 我們來關注command event的回撥, processCommandsCallback函式, 從前面的event機制分析, 一旦s_fdCommand上有資料, 此回撥函式就會被呼叫. (略過onNewCommandConnect的分析)
processCommandsCallback通過 record_stream_get_next阻塞讀取s_fdCommand上發來的 資料, 直到收到一完整的request(request包的完整性由record_stream的機制保證), 然後將其送達processCommandBuffer.
進入processCommandBuffer以後,我們就正式進入了命令的解析部分. 每個命令將以RequestInfo的形式存在.
  1. typedefstruct RequestInfo {  
  2. int32_t token; //this is not RIL_Token
  3. CommandInfo *pCI;  
  4. struct RequestInfo *p_next;  
  5. char cancelled;  
  6. char local; // responses to local commands do not go back to command process
  7. } RequestInfo;  

這裡的pRI就是一個RequestInfo結構指標, 從socket過來的資料流, 前面提到是Parcel處理過的序列化位元組流, 這裡會通過反序列化的方法提取出來. 最前面的是request號, 以及token域(request的遞增序列號). 我們更關注這個request號, 前面提到, 上層和rild之間, 這個號是統一的. 它的定義是一個包含ril_commands.h的列舉, 在ril.cpp中
  1. static CommandInfo s_commands[] = {  
  2. #include "ril_commands.h"
  3. };  

pRI直接訪問這個陣列, 來獲取自己的pCI.
這是一個CommandInfo結構:
  1. typedefstruct {  
  2. int requestNumber;  
  3. void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);  
  4. int(*responseFunction) (Parcel &p, void *response, size_t responselen);  
  5. } CommandInfo;  

基本解析到這裡就完成了, 接下來, pRI被掛入pending的request佇列, 執行具體的pCI->dispatchFunction, 進行詳細解析.
3. request的詳細解析
對dial而言, CommandInfo結構是這樣初始化的:
{RIL_REQUEST_DIAL, dispatchDial, responseVoid},
這裡執行dispatchFunction, 也就是dispatchDial這一函式.我們可以看到其實有很多種類的dispatch function, 比如dispatchVoid, dispatchStrings, dispatchSIM_IO等等, 這些函式的區別, 在於Parcel傳入的引數形式,Void就是不帶引數的,Strings是以string[]做引數,又如Dial等,有自己的引數解析方式,以此類推.
request號和引數現在都有了,那麼可以進行具體的request函式呼叫了.
s_callbacks.onRequest(pRI->pCI->requestNumber, xxx, len, pRI)完成這一操作.
s_callbacks 是上篇文章中提到的獲取自libreference-ril的RIL_RadioFunctions結構指標,request請求在這裡轉入底層的 libreference-ril處理,handler是reference-ril.c中的onRequest.
onRequest進行一個簡單的switch分發,我們依然來看RIL_REQUEST_DIAL
流程是 onRequest-->requestDial-->at_send_command-->at_send_command_full-->at_send_command_full_nolock-->writeline
requestDial中將命令和引數轉換成對應的AT命令,呼叫公共send command介面at_send_command.
除了這個介面之外,還有 at_send_command_singleline,at_send_command_sms,at_send_command_multiline 等,這是根據at返回值,以及發命令流程的型別來區別的.比如at+csq這類,需要at_send_command_singleline,而傳送簡訊,因為有prompt提示符">",傳裸資料,結束符等一系列操作,需要專門用at_send_command_sms來實現.
然後執行at_send_command_full,前面幾個介面都會最終到這裡,再通過一個互斥的at_send_command_full_nolock呼叫,然後完成最終的寫出操作,在writeline中,寫出到初始化時開啟的裝置中.
writeline返回之後,還有一些操作,如儲存type等資訊,供response回來時候使用,以及一些超時處理. 不再詳述.
到這裡,request的詳細流程,就分析完畢了.
response流程
前文對request的分析, 終止在了at_send_command_full_nolock裡的writeline操作,因為這裡完成命令寫出到硬體裝置的操作,接下來就是等待硬體響應,也就是response的過程了。我們的分析也是從這裡開始。
response資訊的獲取,是在第一篇初始化分析中,提到的readerLoop中。由readline函式以‘行’為單位接收上來。
AT的response有兩種,一是主動上報的,比如網路狀態,簡訊,來電等都不需要經過請求,有一unsolicited詞語專門描述。另一種才是真正意義上的response,也就是命令的響應。
這裡我們可以看到,所有的行,首先經過sms的自動上報篩選,因為簡訊的AT處理通常比較麻煩,無論收發都單獨列出。這裡是因為要即時處理這條簡訊訊息(兩行,標誌+pdu),而不能拆開處理。處理函式為onUnsolicited(由s_unsolHandler指向),我們等下介紹。
除開sms的特例,所有的line都要經過processLine,我們來看看這個流程:
processLine
|----no cmd--->handleUnsolicited //主動上報
|----isFinalResponseSuccess--->handleFinalResponse //成功,標準響應
|----isFinalResponseError--->handleFinalResponse //失敗,標準響應
|----get '>'--->send sms pdu //收到>符號,傳送sms資料再繼續等待響應
|----switch s_type--->具體響應  //命令有具體的響應資訊需要對應分析
我們這裡主要關注handleUnsolicited自動上報(會呼叫到前面smsUnsolicite也呼叫的onUnsolicite),以及 switch s_type具體響應資訊,另外具體響應需要handleFinalResponse這樣的標準響應來最終完成。
1. onUnsolicite(主動上報響應)
static void onUnsolicited (const char *s, const char *sms_pdu);
簡訊的AT設計真是麻煩的主,以致這個函式的第二個引數完全就是為它準備的。
response 的主要的解析過程,由at_tok.c中的函式完成,其實就是字串按塊解析,具體的解析方式由每條命令或上報資訊自行決定。這裡不再詳述,onUnsolicited只解析出頭部(一般是+XXXX的形式),然後按型別決定下一步操作,操作為 RIL_onUnsolicitedResponse和RIL_requestTimedCallback兩種。
a)RIL_onUnsolicitedResponse: 
將 unsolicited的資訊直接返回給上層。通過Parcel傳遞,將 RESPONSE_UNSOLICITED,unsolResponse(request號)寫入Parcel先,然後通過 s_unsolResponses陣列,查詢到對應的responseFunction完成進一步的的解析,存入Parcel中。最終通過 sendResponse將其傳遞迴原程序。流程:
sendResponse-->sendResponseRaw-->blockingWrite-->write to s_fdCommand(前面建立起來的和上層框架的socket連線)
這些步驟之後有一些喚醒系統等其他操作。不再詳述。
b)RIL_requestTimedCallback:
通過event機制(參考文章二)實現的timer機制,回撥對應的內部處理函式。通過internalRequestTimedCallback將回調新增到event迴圈,最終完成callback上掛的函式的回撥。比如pollSIMState,onPDPContextListChanged等回撥, 不用返回上層, 內部處理就可以。
2. switch s_type(命令的具體響應)及handleFinalResponse(標準響應)
命令的型別(s_type)在send command的時候設定(參考文章二),有NO_RESULT,NUMERIC,SINGLELINE,MULTILINE幾種,供不同的AT使用。比如AT+CSQ是singleline, 返回at+csq=xx,xx,再加一行OK,比如一些設定命令,就是no_result, 只有一行OK或ERROR。
這幾個型別的解析都很相仿,通過一定的判斷(比較AT頭標記等),如果是對應的響應,就通過 addIntermediate掛到一個臨時結果sp_response->p_intermediates佇列裡。如果不是對應響應,那它其實應該是穿插其中的自動上報,用onUnsolicite來處理。
具體響應,只起一個獲取響應資訊到臨時結果,等待具體分析的作用。無論有無具體響應,最終都得以標準響應handleFinalResponse來完成,也就是接受到OK,ERROR等標準response來結束,這是大多數AT命令的規範。
handleFinalResponse 會設定s_commandcond這一object,也就是at_send_command_full_nolock等待的物件。到這裡,響應的完整資訊已經完全獲得,send command可以進一步處理返回的資訊了(臨時結果,以及標準返回的成功或失敗,都在sp_response中)。
pp_outResponse引數將sp_response返回給呼叫at_send_command_full_nolock的函式。
繼續我們在文章二的分析的話,這個函式其實是requestDial,不過requestDial忽略了響應,所以我們另外看個例子,如requestSignalStrength,命令其實就是前面提到的at+csq:
可以看到確實是通過at_send_command_singleline來進行的操作,response在p_response中。
p_response如果返回失敗(也就是標準響應的ERROR等造成),則通過RIL_onRequestComplete傳送返回資料給上層,結束命令。
如果成功,則進一步分析p_response->p_intermediates, 同樣是通過at_tok.c裡的函式進行分析。並同樣將結果通過RIL_onRequestComplete返回。
RIL_onRequestComplete:
RIL_onRequestComplete和RIL_onUnsolicitedResponse很相仿,功能也一致。
通過Parcel來傳遞迴上層,同樣是先寫入RESPONSE_SOLICITED(區別於 RESPONSE_UNSOLICITED),pRI->token(上層傳下的request號),錯誤碼(send command的錯誤,不是AT響應)。如果有AT響應,通過訪問pRI->pCI->responseFunction來完成具體 response的解析,並寫入Parcel。
然後通過同樣的途徑:
sendResponse-->sendResponseRaw-->blockingWrite-->write to s_fdCommand
完成最終的響應傳遞。
到這裡,我們分析了自動上報與命令響應,其實response部分,也就告一段落了

相關推薦

android sim

Android的RIL驅動模組,在hardware/ril目錄下,一共分rild,libril.so以及librefrence_ril.so三個部分,另有一 radiooptions可供自動或手動除錯使用。都依賴於include目錄中ril.h標頭檔案。目前cupcake分支上帶的是gsm的支援,另有

android實現異網識別運營商網路

檢測的程式碼 private void checkIMSi() {         boolean simStateBySlotIdx = SimUtils.getSimStateBySlotIdx(this, 0);     &n

android-手機登入介面嘗試獲取手機號碼,並可選擇subscriptionId

LogonActivity.java public class LogonActivity extends Activity { private EditText nickET; private EditText passwordET; private E

android的那些程式碼

這陣子忙著整理專案了,所以就沒怎麼出新的文章了,不過下面寫的這篇文章對大家很有幫助。關於雙卡雙待的資訊獲取,包含了imei、phonenumber、operatorName(sim卡生產商,國內就主要指三大運營商了)、NetworkType(這裡就主要是4G、3

Android獲取本機號碼(無法獲取兩個號碼)

        搞了一個想獲取Android手機的本機號碼的功能,但是發現雙卡雙待的手機是無法獲取到兩個號碼 的。在Android的官方文件是沒有提供相應的Api的,因為標準的Andoird是沒有雙卡的,好像也只有國內才會搞雙卡雙待的神器吧。以下記錄一下做這個功能所學習到的

Android

轉自這裡 一、雙卡雙待背景分析 使用者為了兼顧運營商優勢,使用雙卡雙待手機: 雙卡雙待這項技術在發展中國家使用很普遍,因為在發展中國家電信運營商發展不夠成熟,相關管理制度不完善。從使用者的角度出發,主要考慮資費問題,比如:移動通話訊號好,聯通3G上網流暢、流量費相

Android 識別

簡介Android雙卡雙待已經越來越普及了,解決雙卡雙待管理是廣大手機開發人員必須得面對的問題,為實現Android平臺的雙卡雙待操作,筆者研究了Android 應用層操作雙卡雙待的機制。機制獲取基於ITelephony介面實現phone應用中的“phone服務”,通過Tel

android MTK SIM,apn,subid和slotid相關

之前一個專案的需要是需要開啟MTK系統的apn設定的頁面涉及到subid的 大概瞭解下android的sim卡相關, Intent intent = new Intent(Settings.ACTION_APN_SETTINGS); startActivity

Android 解決的問題 mtk,展訊,高通

目前國內對於雙卡智慧手機的需求還是很大的,各種複雜的業務會涉及到雙卡模組;而android標準的api又不提供對雙卡的支援。導致國內雙卡模組標準混亂,各個廠商各玩各的。目前我知道的雙卡解決方案就有:mtk,展訊,高通,broadcom等。 由於公司業務需要,必須要對雙

聚焦鏈改,

在北京 cdd 北京時間 投資 們的 生態 整合 term ces “為了你我用了半年的積蓄,熬著夜來看你……”這說的大概就是蘋果發布會吧 蘋果的新產品發布會在北京時間9月13日淩晨一點舉行相信果粉們應該都沒有錯過這場盛會 然鵝....窮人才看發布會,土豪都是睡醒直接買這次

華為手機聯通3G上網慢的解決辦法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

AI技術的蘋果iPhone XS Max7納米6.5寸512GB頂配12799元(公號回覆“蘋果AI”下載PDF資料)

AI技術的蘋果iPhone XS Max雙卡雙待7納米6.5寸512GB頂配12799元(公號回覆“蘋果AI”下載PDF資料) 原創: 秦隴紀 科學Sciences 今天 科學Sciences導讀:北京時間9月13日凌晨1點、美國時間9月12日上午10點,蘋果2018秋季新品釋出會召

【記錄】 Android 手機獲取兩個IMEI等

1、前言 專案中遇到上傳手機imei的問題。如果手機是雙卡,目前只能獲取預設的imei TelephonyManager mTelephonyMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_

DSDS,模,,單通,單通,概念及相互關係?【轉】

DSDS:雙卡雙待 DualSimDualStandby雙模:就是手機支援2鐘模式,可以有兩種情況:          1)是該手機有兩個卡插槽,一個支援模式A(比如WCDMA),一個支援模式B(比如CDMA2000)          2)天翼國際雙模卡,該卡同時支援CDMA2000和GSM。     

getDeviceId unique device ID IMEI 不唯一 會變問題

最近接到使用者反饋無法登入的情況越來越多,因為我們的app設計上是不能換手機用,也就是綁定了唯一的裝置ID。從反饋上來看,有一個線索是大部分是雙卡雙待的使用者出現這個問題,並且切換過SIM卡。看來getDeviceId這個方法在雙卡雙待手機上獲取IMEI還是有問題的。 ge

(一)

前言: 關於雙卡雙待這個問題,調研了幾個月終於有所進展,通過收集各方面的資料,整理出了這個文件。~~╭(╯^╰)╮ 1.獲取雙卡的subId 方法1: /** * @param slotId:卡槽的序號:0代表卡槽1,1代表卡槽2

智慧手機之的實現方案

雙卡雙待的出現背景:         手機通訊發展到一定程度之後,很多使用者希望擁有或已經擁用多個手機電話號碼,特別是針對那些經常需要出差,需要經常切換SIM卡的商務人士而言,其迫切希望能將自己的手機承載多個電話號碼, 根據市場上的這一需求,能同時支援兩張SIM卡的

android發簡訊,基於5.1.1實現

【原創】作品,轉載請註明出處,請尊重作者的辛苦。 最近開發中遇到了雙卡的問題,關於雙卡查看了好多文章,但是沒有一個能解決問題的,要麼就是定製的或者有廠商提供支援的,我這裡是基於android 5.1.1實現的雙卡傳送簡訊,這裡需要用的反射,下面直接上程式碼,供大家參考:

Centos 6.5IP網關配置

ip地址配置因公司業務需要需在服務器上配置電信,聯通兩個運營商的IP地址,實現數據分別從兩個地址傳輸,即兩個IP地址都能與外界網絡互通。當時我發現在服務器的兩塊網卡上分別配置兩個IP地址及網關,重啟網絡服務之後,系統會默認選取其中一塊網卡的網關做為數據傳輸網關,這樣造成的後果就是一塊網卡無法與外界通信,後來手

QNX學習筆記 [IMX6Q/TQIMX6Q]製作SD dos+qnx6 分割槽

1.如果已經進入qnx系統,則直接利用qnx fdisk命令 製作FAT32啟動分割槽並掛載到/boot_dos fdisk /dev/sd20 show fdisk /dev/sd20 add -b -t 12 -p 5 mount -e /dev/sd20 mkdosfs -F 3