Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> [Android系統的移植與平台開發]為Android啟動加速

[Android系統的移植與平台開發]為Android啟動加速

編輯:Android開發實例

Android的啟動速度一直以來是他的诟病,雖然現在Android設備的硬件速度越來越快,但是隨著新版本的出現,其啟動速度一直都比較慢,當然,作為程序員,我們是可以理解的,智能手機本身就要啟動很多服務來支持應用的功能,並且Android系統大部分還是使用的Java語言編寫的,必然要運行在Java虛擬機裡,這也決定了它運行速度和啟動速度都相對較慢。同時,Android系統為了在執行用戶應用程序時提高用戶體驗,還做了一些預加載機制,這也犧牲了開機啟動時間。

根據Android啟動過程的分析可知,我們可以進行定制加速如下:

Ø  定制本地服務

Ø  定制Android系統服務

Ø  優化ZygoteInit的類預加載preloadClasses和資源預加載preloadResources機制

Ø  PackageManagerService掃描、檢查APK安裝包信息

下面我們依次來分析其實現步驟。

 

1. 定制本地服務

由第二章,第2節可知,本地服務都是由C或C++編寫,它們都執行在Linux空間,在init進程的啟動過程中啟動了很多本地服務,如果我們的設備中沒有電話模塊、藍牙模塊,我們可以將這些沒用的本地服務在init.rc裡注釋掉。

396 #service ril-daemon /system/bin/rild

397#     class main

398#     socket rild stream 660 root radio

399#     socket rild-debug stream 660 radio system

400#     user root

401#     group radio cache inet misc audio sdcard_rw log

 

435 service dbus /system/bin/dbus-daemon --system --nofork

436     class main

437 #    socket dbus stream 660 bluetooth bluetooth

438     user bluetooth

439     group bluetooth net_bt_admin

 

441 #service bluetoothd /system/bin/bluetoothd -n

442 #    class main

443 #    socket bluetooth stream 660 bluetooth bluetooth

444 #    socket dbus_bluetooth stream 660 bluetooth bluetooth

445     # init.rc does not yet support applying capabilities, so run as root and

446     # let bluetoothd drop uid to bluetooth with the right linux capabilities

447 #    group bluetooth net_bt_admin misc

448 #    disabled

 

重新編譯system.img然後啟動模擬器即可。

筆者做了對比,去掉上述幾個本地服務與沒有去掉本地服務,二者在開機時間上幾乎沒有減少多少,這也可以理解,因為本地服務就是幾個程序,少執行和多執行幾個程序對於總體開機時間沒有多大影響,不過,去掉沒有使用的本地服務,對整個系統性能來說,會有微不足道的提升。

如果去掉開機動畫服務可以大大的提高系統的啟動速度:

  1. 433 #service bootanim /system/bin/bootanimation  
  2. 434 #    class main  
  3. 435 #    user graphics  
  4. 436 #    group graphics  
  5. 437 #    disabled  
  6. 438 #    oneshot  
  7.  

 

2. 定制Android系統服務

由Android的啟動過程可知,init進程啟動了app_process作為zygote,在app_process裡啟動了Dalvik虛擬機,然後加載執行了第一個Java程序ZygoteInit作為Dalvik主線程,在ZygoteInit裡fork了第一個Java程序SystemServer,在SystemServer裡啟動了大量的Android的核心服務,通常來說這些服務一般不要去動,如果我們的設備裡沒有使用過某些服務,並且將來也明確不使用,可以將其去掉。

我們先來看看SystemServer啟動了哪些Android服務:

EntropyService:熵(shang)服務,用於產生隨機數

PowerManagerService:電源管理服務

ActivityManagerService:最核心服務之一,Activity管理服務

TelephonyRegistry:電話服務,電話底層通知服務

PackageManagerService:程序包管理服務

AccountManagerService:聯系人帳戶管理服務

ContentService:內容提供器的服務,提供跨進程數據交換

LightsService:光感應傳感器服務

BatteryService:電池服務,當電量不足時發廣播

VibratorService:震動器服務

AlarmManagerService:鬧鐘服務

WindowManagerService:窗口管理服務

BluetoothService:藍牙服務

InputMethodManagerService:輸入法服務,打開關閉輸入法

AccessibilityManagerService:輔助管理程序截獲所有的用戶輸入,並根據這

些輸入給用戶一些額外的反饋,起到輔助的效果,View的點擊、焦點等事件分發管理服務

DevicePolicyManagerService:提供一些系統級別的設置及屬性

StatusBarManagerService:狀態欄管理服務

ClipboardService:粘貼板服務

NetworkManagementService:手機網絡管理服務

TextServicesManagerService:

NetworkStatsService:手機網絡狀態服務

NetworkPolicyManagerService:

WifiP2pService:Wifi點對點直聯服務

WifiService:WIFI服務

ConnectivityService:網絡連接狀態服務

ThrottleService:modem節流閥控制服務

MountService:磁盤加載服務,通常也mountd和vold服務結合

NotificationManagerService:通知管理服務,通常和StatusBarManagerService

DeviceStorageMonitorService:存儲設備容量監聽服務

LocationManagerService:位置管理服務

CountryDetectorService:檢查當前用戶所在的國家

SearchManagerService:搜索管理服務

DropBoxManagerService:系統日志文件管理服務(大部分程序錯誤信息)

WallpaperManagerService:壁紙管理服務

AudioService:AudioFlinger上層的封裝的音量控制管理服務

UsbService:USB Host和device管理服務

UiModeManagerService:UI模式管理服務,監聽車載、座機等場合下UI的變化

BackupManagerService:備份服務

AppWidgetService:應用桌面部件服務

RecognitionManagerService:身份識別服務

DiskStatsService:磁盤統計服務

SamplingProfilerService:性能統計服務

NetworkTimeUpdateService:網絡時間更新服務

天啊,43個Android服務,

除了對原生的Android系統定制外,還可以通過引入外部技術來提升開機速度,目前有人使用Berkeley Lab Checkpoint/Restart(BLCR)技術給系統做一個快照,類似於Vmware裡用的SnapeShot和Windows裡的休眠機制,它能將當前Android環境保存在一個文件裡,當下次啟動的時候從該文件恢復Android運行環境,這種方式可以明顯的提升啟動速度,其實現過程比較復雜。

BLCR技術細節後續再完善。。。

 

3. PackageManagerService

PackageManagerService是Android的包管理器,主要用來管理Android系統中的APK文件,在SystemServer裡,通過ServerThread調用PackageManagerService.main()啟動了包管理服務。
 

PackageManagerService的主要作用有:

3.1  @PackageManagerService.main()

生成一個IPackageManager接口,也就是PackageManagerService。
public static final IPackageManager main(Context context, boolean factoryTest) {
        PackageManagerService m = new PackageManagerService(context, factoryTest);
        ServiceManager.addService("package", m);
        return m;
    }

3.2  PackageManagerService構造方法中,首先會進行一些成員變量的初始化,比如mContext, mFactoryTest, mMetrics, mSettings等。
最重要的是初始化mInstaller這個變量。Installer是一個很重要的類,所有對apk的install, uninstall,move等操作,都是通過它進行的。
    Installer installer = new Installer();
        if (installer.ping() && Process.supportsProcesses()) {
            mInstaller = installer;
        } else {
            mInstaller = null;
        }


3.3  建立PackageHandler消息循環,用於處理外部的apk安裝請求消息,如adb install,packageinstaller安裝apk時會發送消息
    mHandlerThread.start();
        mHandler = new PackageHandler(mHandlerThread.getLooper());

3.4  解析/system/etc/permission下xml文件(framework/base/data/etc/),包括platform.xml和系統支持的各種硬件模塊的feature。

   主要工作:
  (1)建立底層user ids和group ids 同上層permissions之間的映射;可以指定一個權限與幾個組ID對應。當一個APK被授予這個權限時,它也同時屬於這幾個組。
  (2)給一些底層用戶分配權限,如給shell授予各種permission權限;把一個權限賦予一個UID,當進程使用這個UID運行時,就具備了這個權限。
  (3) library,系統增加的一些應用需要link的擴展jar庫;
  (4) feature,系統每增加一個硬件,都要添加相應的feature.將解析結果放入mSystemPermissions,mSharedLibraries,mSettings.mPermissions,mAvailableFeatures等幾個集合中供系統查詢和權限配置使用。


3.5  檢查/data/system/packages.xml是否存在,這個文件是在解析apk時由writeLP()創建的,裡面記錄了系統的permissions,以及每個apk的name,codePath,flags,ts,version,uesrid等信息,這些信息主要通過apk的AndroidManifest.xml解析獲取,解析完apk後將更新信息寫入這個文件並保
存到flash,下次開機直接從裡面讀取相關信息添加到內存相關列表中。當有apk升級,安裝或刪除時會更新這個文件。

3.6 檢查BootClassPath,mSharedLibraries及/system/framework下的jar是否需要dexopt,需要的則通過dexopt進行優化。

3.7 啟動AppDirObserver線程監測/system/framework,/system/app,/data/app,/data/app-private目錄的事件,主要監聽add和remove事件。對於目錄監聽底層通過inotify機制實現,inotify 是一種文件系統的變化通知機制,如文件增加、刪除等事件可以立刻讓用戶態得知,它為用戶態監視文件系統的變化提供了強大的支持。
 

  • 當有add event時調用scanPackageLI(File , int , int)處理;
  • 當有remove event時調用removePackageLI()處理;


3.8  對於以上幾個目錄下的apk逐個解析,主要是解析每個apk的AndroidManifest.xml文件,處理asset/res等資源文件,建立起每個apk的配置結構信息,並將每個apk的配置信息添加到全局列表進行管理。調用installer.install()進行安裝工作,檢查apk裡的dex文件是否需要再優化,如果需要優化則通過輔助工具dexopt進行優化處理;將解析出的componet添加到pkg的對應列表裡;
對apk進行簽名和證書校驗,進行完整性驗證。

3.9  將解析的每個apk的信息保存到packages.xml和packages.list文件裡,packages.list記錄了如下數據:pkgName,userId,debugFlag,dataPath(包的數據路徑)

 

其中對/system/framework,/system/app,/data/app,/data/app-private目錄中的APK掃描耗費了大量的時間,通過下面的筆者的實驗結果可以看得出來。


 無優化時的APK總計有50個,減少APK時APK只有5個,包掃描的時間減少了4秒,Android服務啟動的時間減少了近10秒,整個系統的啟動時間減少了15秒左右

在減少APK的情況下,然後將開機動畫關閉了,本地服務啟動時間略有減少,預加載類與資源時減少了近10秒,包掃描時間減少了0.5秒左右,Android服務啟動時間減少近4秒,整個系統啟動時間減少了近15秒。

由此可見,減少APK的數量關閉開機動畫可以明顯的提高Android的啟動速度。

至於關閉其它本地服務對啟動時間影響不大的原因,我的感覺是本地服務注冊到Binder之後就等待框架客戶端的連接,而關閉開機動畫對啟動速度影響之大,通過分析bootanim可知,在開啟動畫時要開啟一個線程,mask圖片在前面作為幕布,shine圖片在後面每隔一定時間重新繪制一次,每次繪制時通過調用OPENGL的api調用2D加速來繪制圖片,而我們使用的模擬器,全部操作通過軟件來模擬,所以對系統怕啟動速度影響比較大。如果在具體的設備上執行對啟動速度的影響應該比這要小,具體硬件設備上優化,後續會有博文推出。


 

4. Android系統企業級定制

在做Android產品開發的過程中,經常會有客戶說:“我們不想讓我們的產品開機後看到Android系統的桌面,我們希望設備開機會直接進入我們自己的程序“。“我們的產品就是直接面對最終用戶的,其它的無關的功能不需要。”比如說,之前我們開發的一款社區醫療軟件,通過藍牙和心電儀、血糖儀等采集外設通信,客戶要求開機進入醫療軟件,通過底層藍牙通信,我們采用的就是定制的Android平板的桌面。

通常定制應用程序開機啟動有兩種實現方式:

Ø  接收系統啟動廣播:BOOT_COMPLETED,在廣播接收器代碼裡實現應用程序的啟動。

Ø  編寫一個桌面程序,替換掉系統默認的Launcher應用。

第一種方式實現簡單,但是這個應用程序是在Android系統桌面出現之後再啟動的,不是真正意義上的產品定制,並且,如果當前的應用程序崩潰了退出後,會回到桌面上,當然我們可以實現崩潰後再次重新啟動,但是,這終究不是真正意義上的定制。

第二種實現方式思路:當系統啟動完畢之後,系統會發出一個Action為android.intent.action.MAIN,category為android.intent.category.HOME的Intent,默認系統的Launcher桌面會響應這個Intent,那麼,我們可以編寫一個應用程序,讓它去響應這個Intent,然後我們將這個應用程序替換掉系統默認的Launcher桌面。系統重新啟動之後,會自動啟動我們自己的應用。但是,如果一些非法程序也響應這個Intent,那麼照樣不能達到客戶的目的。這個時候,我們就要去修改系統框架代碼,讓Android系統啟動完畢之後發送我們自己定義的Intent而不是公開的category為HOME的 Intent。

思路如下:

Ø  添加一個新的category:android.intent.category.FS_HOME

Ø  將框架裡面所有發送android.intent.category.HOME的Intent全部改成android.intent.category.FS_HOME

category的定義文件在:

frameworks/base/core/java/android/content/Intent.java

2218     /**

2219      * This is the home activity, that is the first activity that is displayed

2220      * when the device boots.

2221      */

2222     @SdkConstant(SdkConstantType.INTENT_CATEGORY)

2223     public static final String CATEGORY_HOME = "android.intent.category.HOME";

 

在CATEGORY_HOME後面添加下面兩行代碼:

2224     @SdkConstant(SdkConstantType.INTENT_CATEGORY)

2225     public static final String CATEGORY_FS_HOME = "android.intent.category.FS_HOME";

 

通過grep CATEGORY_HOME frameworks/ -R命令查找所有使用CATEGORY_HOME的文件:

./frameworks/ex/carousel/test/src/com/android/carouseltest/TaskSwitcherActivity.java

./frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

./frameworks/base/services/java/com/android/server/am/ActivityRecord.java

./frameworks/base/services/java/com/android/server/UiModeManagerService.java

./frameworks/base/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java

./frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

./frameworks/base/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java

 

將文件裡使用CATEGORY_HOME常量的地方全部改為CATEGORY_FS_HOME。

新建一個Android應用:MyLauncher,在其AndroidManifest.xml裡,<intent-filter>標簽裡添加上響應CATEGORY_FS_HOME的代碼:

<activity android:name=".MyLauncherActivity">

        <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.FS_HOME" />

                   <category android:name="android.intent.category.DEFAULT" />

        </intent-filter>

</activity>

 

重新編譯frameworks/base、frameworks/ex:

$ source build/envsetup.sh

$ make

重新運行模擬器,使用新編譯的Android系統,可以看到系統啟動起來就進入我們的MyLauncher應用,從實現實現桌面的替換。

 

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