2025-05-24

ok, 通過前面講解,系統已經從 init 進程  –> 啟動 zygote –> 啟動 SystemServer –> ??? 那麼現在應該啟動什麼呢?

 

從前面分析來看,基本的native及 java 世界的環境都已建立完成,那麼還差一個HOME主頁顯示? 可視化系統下面即將開始瞭。

在講解 Zygote 中,有一個函數:

main @ frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

 

這裡利用  runSelectLoopMode() 函數處理客戶連接及客戶請求

private static void runSelectLoopMode(){

while (true) {

// 利用select進行多路I/O 監聽

index = selectReadable(fdArray);

// 如果有客戶端連接則accept並加入到ArrayList中

if (index == 0) {

                ZygoteConnection newPeer = acceptCommandPeer();

                peers.add(newPeer);

                fds.add(newPeer.getFileDesciptor());

       }else {

// 否則交給ZygoteConnection的 runOnce()函數

done = peers.get(index).runOnce();

}

}

}

–>

上面在客戶端連接使用 ZygoteConnection 類,具體 runOnce()功能如下:

runOnce @ frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

args = readArgumentList();

// 根據客戶端給定的參數,利用 forkAndSpecialize 創建進程

pid = Zygote.forkAndSpecialize(parsedArgs.uid,

                    parsedArgs.gid,

                    parsedArgs.gids,

                    parsedArgs.debugFlags, rlimits);

 // 根據pid值進行處理子進程及父進程

        if (pid == 0) {

            // in child

            handleChildProc(parsedArgs, descriptors, newStderr);

            // should never happen

            return true;

        } else { /* pid != 0 */

            // in parent…pid of < 0 means failure

            return handleParentProc(pid, descriptors, parsedArgs);

        }

}

總結:客戶端利用Zygote代表 ZygoteConnection 類請求 zygote 創建新的進程,創建成功後並分別對子進程及父進程單獨流程處理。

 

應用安裝完畢後,還需要有一個HOME應用來負責將它們在桌面上顯示出來,默認就是Launcher2應用程序,這裡將介紹一下 Launcher2 啟動過程, 主要分為6個大過程來啟動:

 

在 SystemServer.java 中對於 ActivityManagerService 的處理簡單說明下:

1、ActivityManagerService.main(factoryTest);

通過AThread線程對象來內部創建瞭一個ActivityManagerService實例,然後將這個實例保存其成員變量mService中,接著又把這個ActivityManagerService實例保存在ActivityManagerService類的靜態成員變量mSelf中 :

ActivityManagerService m = new ActivityManagerService();

mService = m;

mSelf = mService;

2、ActivityManagerService.setSystemProcess();

系統中的應用程序的所有信息都保存在PackageManagerService,所需要的應用信息從這裡提取即可。

ApplicationInfo info =

               mSelf.mContext.getPackageManager().getApplicationInfo(

                        "android", STOCK_PM_FLAGS);

mSystemThread.installSystemApplicationInfo(info);

3、在run() 函數後半段,有很多的 xxx.systemReady();這裡是通知各個服務,系統已經準備就緒。

其中如下代碼片段:

// We now tell the activity manager it is okay to run third party

// code.  It will call back into us once it has gotten to the state

// where third party code can really run (but before it has actually

// started launching the initial applications), for us to complete our

// initialization.

((ActivityManagerService)ActivityManagerNative.getDefault())

                .systemReady()

–>

systemReady @ frameworks\base\services\java\com\android\server\am\ActivityManagerSe

rvice.java

public void systemReady(final Runnable goingCallback){

resumeTopActivityLocked(null);  // 這裡啟動Home應用程序

}

–>

private final boolean resumeTopActivityLocked(HistoryRecord prev){

// Find the first activity that is not finishing.

HistoryRecord next = topRunningActivityLocked(null);

if (next == null) {

     // There are no more activities!  Let's just start up the

     // Launcher…

     return startHomeActivityLocked();

}

}

利用topRunningActivityLocked 返回的是當前系統Activity堆棧最頂端的Activity 而為 null 則調用 topRunningActivityLocked()

4、啟動HOME應用程序

private boolean startHomeActivityLocked() {

if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {

            intent.addCategory(Intent.CATEGORY_HOME);

}

ActivityInfo aInfo =

             intent.resolveActivityInfo(mContext.getPackageManager(),STOCK_PM_FLAGS);

ProcessRecord app = getProcessRecordLocked(aInfo.processName,aInfo.applicationInfo.uid);

if (app == null || app.instrumentationClass == null) {

startActivityLocked(null, intent, null, null, 0, aInfo,

                        null, null, 0, 0, 0, false, false);

}

}

這裡會創建一個 CATEGORY_HOME 類型的 Intent ,通過resolveActivityInfo函數向 PackageManagerService 查詢 CATEGORY 是否類型為 HOME 類型應用。這裡返回 com.android.launcher2.Launcher 這個 Activity。第一次啟動則利用startActivityLocked啟動這個Activity。

查看 packages\apps\Launcher2\AndroidManifest.xml 內容:

<intent-filter>

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

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

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

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

</intent-filter>

5、下面就啟動 com.android.launcher2.Launcher 這個 Activity

首先從執行  onCreate 函數開始簡單過一下代碼調用大致關系:

onCreate –> mModel.startLoader(this, true); –>

調用到 LauncherModel.java

public void startLoader(Context context, boolean isLaunching)

這裡並非直接加載應用程序,而是利用發消息由LoaderThread處理

mLoaderThread = new LoaderThread(context, oldThread, isLaunching);

mLoaderThread.start();

–>

public void run() {

waitForOtherThread();

if (loadWorkspaceFirst) {

   if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");

      loadAndBindWorkspace();

} else {

   if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps");

     loadAndBindAllApps();

}

// second step

if (loadWorkspaceFirst) {

    if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");

     loadAndBindAllApps();

    } else {

    if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace");

     loadAndBindWorkspace();

    }

}

這裡調用 loadAndBindAllApps 進一下操作www.aiwalls.com

private void loadAndBindAllApps() {

loadAllAppsByBatch();

}

 

private void loadAllAppsByBatch() {

// 先構造一個  CATEGORY_LAUNCHER 類型的 Intent

final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

 

// 利用 queryIntentActivities 所有類型為 Intent.ACTION_MAIN 及

// Intent.CATEGORY_LAUNCHER 的 Activity

final PackageManager packageManager = mContext.getPackageManager();

apps = packageManager.queryIntentActivities(mainIntent, 0);

 

//  保存於 mAllAppsList 應用列表中

for (int j=0; i<N && j<batchSize; j++) {

   // This builds the icon bitmaps.

   mAllAppsList.add(new ApplicationInfo(apps.get(i), mIconCache));

   i++;

}

 

// 通過 Callbacks

final Callbacks callbacks = tryGetCallbacks(oldCallbacks);

mHandler.post(…) {

callbacks.bindAllApplications(added);

   }

}

–>

/**

 * Add the icons for all apps.

 *

 * Implementation of the method from LauncherModel.Callbacks.

*/

public void bindAllApplications(ArrayList<ApplicationInfo> apps) {

      mAllAppsGrid.setApps(apps);

}

 

6、AllApps2D.java 繼續加載應用程序

public void setApps(ArrayList<ApplicationInfo> list) {

    mAllAppsList.clear();

    addApps(list);

}

public void addApps(ArrayList<ApplicationInfo> list){

final int N = list.size();

for (int i=0; i<N; i++) {

final ApplicationInfo item = list.get(i);

    int index = Collections.binarySearch(mAllAppsList, item,

                    LauncherModel.APP_NAME_COMPARATOR);

    if (index < 0) {

           index = -(index+1);

    }

    mAllAppsList.add(index, item);

}

mAppsAdapter.notifyDataSetChanged();

}

 

這裡創建瞭 ApplicationInfo 實例 ,即在桌面上顯示每個應用程序圖標,點擊即可啟動這些應用程序。

而點擊最右邊中間 MENU 按扭時由如下函數完成:

    /**

     * Launches the intent referred by the clicked shortcut.

     *

     * @param v The view representing the clicked shortcut.

     */

public void onClick(View v) {

showAllApps(true);

}

–>

    void showAllApps(boolean animated) {

        mAllAppsGrid.zoom(1.0f, animated);

        ((View) mAllAppsGrid).setFocusable(true);

        ((View) mAllAppsGrid).requestFocus();

       

        // TODO: fade these two too

        mDeleteZone.setVisibility(View.GONE);

}

 

將會顯示系統中所有的應用,而點擊具體的某個圖標時:

AllApps2D.java @ AllApps2D.java

public void onItemClick(AdapterView parent, View v,

             int position, long id) {

        ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);

        mLauncher.startActivitySafely(app.intent, app);

}

調用 startActivitySafely 則啟動相應的應用程序

 

總結:

這一節涉及到的東西太多太多,這裡也隻是簡要的過瞭一下代碼,還有很多的概念需要弄明白,但至少的知道其基本的流程步驟。

最後以一幅圖結束android系統啟動之框架:

  

摘自  andyhuabing的專欄 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *