Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 深入分析Android開機找網延遲

深入分析Android開機找網延遲

編輯:關於Android編程

一般來說,phone的屬性是persistent為true,而因此phone進程也是較早被叫起,被android:presistent修飾的應用在系統啟動之後會被AM啟動,即便沒有運行,AM也會調用startProcessLocked啟動該進程。啟動package com.android.phone 即phone application,這會直接call到PhoneApp的onCreate(),執行初始化找網的動作。

我們查看源碼如下:

alps\packages\services\Telephony\AndroidManifest.xml

android:persistent="true"

......

那麼phone被正常叫起的log應該如下:

01-01 14:01:47.890: I/ActivityManager(717): Start proc com.android.phone for added application com.android.phone: pid=991 uid=1001 gids={41001, 3002, 3001, 3003, 1028, 1015, 1004, 2002, 1023}
從上面log中可以看到Phone進程正常叫起。但是我們去查看找網延遲的手機去復現的時候發現,Phone進程並不是正常叫起,而是被run在Phone進程中的組件所啟動,參考log如下:

01-29 14:08:29.842: I/ActivityManager(723): Start proc com.android.phone for service com.mediatek.CellConnService/.PhoneStatesMgrService: pid=990 uid=1001 gids={41001, 3002, 3001, 3003, 1028, 1015, 1004, 2002, 1023}
從上面log中可以看到當前phone進程是由CellConnService.PhoneStatesMgrService服務叫起,我們查看PhoneStatesMgrService源碼發現,該服務作為phone的一個組件運行在phone進程中。參考源碼如下:

android:process="com.android.phone"//通過這個android:process="com.android.phone"屬性,我們可以指定某個組件運行的進程。我們可以通過設置這個屬性,讓每個組件運行在它自己的進程中,也可以只讓某些組件共享一個進程。我們要可以通過設置“android:process”屬性,讓不同應用程序中的組件運行在相同的進程中。這裡com.mediatek.CellConnService作為一個組件運行在com.android.phone中
android:allowClearUserData="false"
......


CELLCONNSERVICE" />



那麼如果phone進程是由phone的接口叫起,那麼就無法執行初始化找網的操作,而是等到alps\packages\services\telephony\AndroidManifest.xml 中OtaStartUpReceiver接收BOOT_COMPLETED後才能叫起PhoneApp,進而才執行它的onCreate()進行初始化找網的操作。這樣無疑會導致找網延遲。那麼此時我們需要排查哪裡啟動了PhoneStagtesMgrService。這裡我們需要關注一下上面加粗標紅的一個Action---CELLCONNSERVICE,然後我們接著分析log,參考log如下:

01-29 14:08:29.764: W/ContextImpl(882): Implicit intents with startService are not safe: Intent { act=android.intent.action.CELLCONNSERVICE } android.content.ContextWrapper.startService:494 com.mediatek.CellConnService.CellConnMgr.register:159 com.android.systemui.huawei.MobileStateManager.:106
01-29 14:08:29.852: W/ContextImpl(882): Implicit intents with startService are not safe: Intent { act=android.intent.action.CELLCONNSERVICE } android.content.ContextWrapper.bindService:517 com.mediatek.CellConnService.CellConnMgr.register:160 com.android.systemui.huawei.MobileStateManager.:106
01-29 14:08:32.294: W/ContextImpl(882): Implicit intents with startService are not safe: Intent { act=android.intent.action.CELLCONNSERVICE } android.content.ContextWrapper.startService:494 com.mediatek.CellConnService.CellConnMgr.register:159 com.android.systemui.huawei.MobileStateManager.:106
01-29 14:08:32.307: W/ContextImpl(882): Implicit intents with startService are not safe: Intent { act=android.intent.action.CELLCONNSERVICE } android.content.ContextWrapper.bindService:517 com.mediatek.CellConnService.CellConnMgr.register:160 com.android.systemui.huawei.MobileStateManager.:106

從上面的log我們看到MobileStateManager通過Intent啟動了一個服務,而接收該Intent的服務恰恰是PhoneStagtesMgrService,參考代碼如下:

代碼一:此處時啟動PhoneStatesMgrService的接口,位於CellConnServic下的CellConnMgr的類中。
public void register(Context ctx) {
Log.d(TAG, "register");


mCtx = ctx;


Intent it = new Intent("android.intent.action.CELLCONNSERVICE");
mCtx.startService(it);
mCtx.bindService(it, mConnection, Context.BIND_AUTO_CREATE);
}
代碼二: 此處是systemui下的MobileStateManager中構造函數的調用
public MobileStateManager(Context context) {
mContext = context;
mCellConnMgr = new CellConnMgr(null);
//mCellConnMgr.register(mContext);//這裡調用了啟動PhoneStatesMgrService服務的接口
mITelephony = getITelephony();
mConnManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
updateSIMInfoList();
}

因此我們在這裡進行代碼的優化,從而問題得到解決。

需要注意的是作為一個組件run在com.android.phone進程中的不只是com.mediatek.CellConnService,例如還有com.android.providers.telephony等,這裡我也把com.android.providers.telephony叫起com.android.phone的分析方法與大家分享一下。

下面是通過調用com.android.providers.telephony叫起com.android.phone進程的log,如下:

01-30 11:02:44.750: I/ActivityManager(714): Start proc com.android.phone for content provider com.android.providers.telephony/.TelephonyProvider: pid=999 uid=1001 gids={41001, 3002, 3001, 3003, 1028, 1015, 1004, 2002, 1023}
從上面log中可以看到此次phone進程是由com.android.providers.telephony/.TelephonyProvider叫起,下面排查TelephonyProvider如何叫起Phone進程的。
首先通過查看源碼確認可以如下:
com.android.phone"
android:allowClearUserData="false"
android:allowBackup="false"
android:label="@string/app_label"
android:icon="@drawable/ic_launcher_phone">


android:authorities="telephony"
android:exported="true"
android:multiprocess="false" />

android:authorities="cb"
android:exported="true"
android:multiprocess="false" />

android:authorities="sms"
android:exported="true"
android:multiprocess="false"
android:readPermission="android.permission.READ_SMS"
android:writePermission="android.permission.WRITE_SMS" />

android:authorities="wappush"
android:exported="true"
android:multiprocess="false" />

android:authorities="mms"
android:exported="true"
android:multiprocess="false"
android:readPermission="android.permission.READ_SMS"
android:writePermission="android.permission.WRITE_SMS">



android:authorities="mms-sms"
android:exported="true"
android:multiprocess="false"
android:readPermission="android.permission.READ_SMS"
android:writePermission="android.permission.WRITE_SMS" />

android:authorities="usersms"
android:exported="true"
android:multiprocess="false"
android:readPermission="android.permission.READ_SMS"
android:writePermission="android.permission.WRITE_SMS" />
android:authorities="usercb"
android:exported="true"
android:multiprocess="false"
android:readPermission="android.permission.READ_SMS"
android:writePermission="android.permission.WRITE_SMS" />
android:authorities="usermms"
android:exported="true"
android:multiprocess="false"
android:readPermission="android.permission.READ_SMS"
android:writePermission="android.permission.WRITE_SMS">






從上面源碼來看TelephonyProvider屬於com.android.phone進程,可通過調用TelephonyProvider來啟動phone進程,因此進一步排查,從下面log來看可以判斷出進程id為878的com.mediatek.systemui中ActivityManager調用TelephonyProvider,而使TelephonyProvider Run在phone進程,進而啟動了com.andorid.phone進程,也就是說我們通過叫起了TelephonyProvider間接叫起了phone進程,叫起TelephonyProvider的常規方法就是通過“content://telephony",這裡要重點關注android:authorities="telephony";
01-30 11:02:44.640: D/SignalClusterView(878): setWifiIndicators, visible=false, strengthIcon=com.mediatek.systemui.ext.IconIdWrapper@426584f0, activityIcon=com.mediatek.systemui.ext.IconIdWrapper@42658508, contentDescription=Wi-Fi 連接已斷開
01-30 11:02:44.643: V/PhoneStatusBar(878): carrierlabel for Gemini=android.widget.LinearLayout{42563b40 I.E..... ......I. 0,0-0,0 #7f080013 app:id/carrier_label_gemini} show=true
01-30 11:02:44.658: D/ActivityManager(714): getContentProviderImpl: from callerandroid.app.ApplicationThreadProxy@42ab1f60 (pid=878) to get content provider telephony
01-30 11:02:44.750: I/ActivityManager(714): Start proc com.android.phone for content provider com.android.providers.telephony/.TelephonyProvider: pid=999 uid=1001 gids={41001, 3002, 3001, 3003, 1028, 1015, 1004, 2002, 1023}
從上面log來看是878進程(systemui)叫起了com.android.providers.telephony/.TelephonyProvider(進程id為999),也就是說是systemui叫起了TelephonyProvider,進而叫起了com.android.phone進程。參考log如下:

01-30 11:02:42.133: I/SurfaceFlinger(146): EventThread Client Pid (714) created

因此我們需要排查systemui中的的代碼,參考排查方法如下:

01-30 11:02:44.640: D/SignalClusterView(878): setWifiIndicators, visible=false, strengthIcon=com.mediatek.systemui.ext.IconIdWrapper@426584f0, activityIcon=com.mediatek.systemui.ext.IconIdWrapper@42658508, contentDescription=Wi-Fi 連接已斷開
01-30 11:02:44.643: V/PhoneStatusBar(878): carrierlabel for Gemini=android.widget.LinearLayout{42563b40 I.E..... ......I. 0,0-0,0 #7f080013 app:id/carrier_label_gemini} show=true
01-30 11:02:44.658: D/ActivityManager(714): getContentProviderImpl: from callerandroid.app.ApplicationThreadProxy@42ab1f60 (pid=878) to get content provider telephony
01-30 11:02:44.750: I/ActivityManager(714): Start proc com.android.phone for content provider com.android.providers.telephony/.TelephonyProvider: pid=999 uid=1001 gids={41001, 3002, 3001, 3003, 1028, 1015, 1004, 2002, 1023}
從上面log來看是878進程(systemui)叫起了com.android.providers.telephony/.TelephonyProvider(進程id為999),也就是說依然是systemui叫起了TelephonyProvider,進而叫起了com.android.phone進程。
然後根據log中來看在叫起TelephonyProvider進程前,上面標紅的地方(878為systemui進程)作了操作,下面是源碼中的調用關系,從下面源碼來看的確有很多地方調用了TelephonyProvider,如HuaweiQuickSettingsController等。需要排查一下這些地方為何調用。

SimInfoManager類中
public static final Uri CONTENT_URI =
Uri.parse("content://telephony/siminfo");
......
public static List getInsertedSimInfoList(Context ctx) {
logd("[getInsertedSimInfoList]+");
ArrayList simList = new ArrayList();
Cursor cursor = ctx.getContentResolver().query(CONTENT_URI,
null, SLOT + "!=" + SLOT_NONE, null, null);//這裡調用了TelephonyProvider
try {
if (cursor != null) {
while (cursor.moveToNext()) {
simList.add(fromCursor(cursor));
}
}
} finally {
if (cursor != null) {
cursor.close();
}
}
logd("[getInsertedSimInfoList]- " + simList.size() + " infos return");
return simList;
}

SIMHelper類中
private static List getSortedSIMInfoList(Context context) {
List simInfoList = SimInfoManager.getInsertedSimInfoList(context);
Collections.sort(simInfoList, new Comparator() {
.....
PhoneStatusBar類中

public void showSimIndicator(String businessType) {
if (mIsSimIndicatorShowing) {
hideSimIndicator();
}
mBusinessType = businessType;
long simId = SIMHelper.getDefaultSIM(mContext, businessType);
Xlog.d(TAG, "showSimIndicator, show SIM indicator which business is " + businessType + " simId = "+simId+".");
if (simId == android.provider.Settings.System.DEFAULT_SIM_SETTING_ALWAYS_ASK) {
List simInfos = SIMHelper.getSIMInfoList(mContext);
....
在源碼中有很多調用的地方,或許是為了獲取sim的狀態而調用了TelephonyProvider,具體繁瑣的log和代碼就不解釋了。

到此整個分析過程都在這裡了,如有疑問可以發消息給我,一起來討論。



  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved