Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android資訊 >> 理解 Android 進程啟動之全過程

理解 Android 進程啟動之全過程

編輯:Android資訊

一. 概述

Android系統將進程做得很友好的封裝,對於上層app開發者來說進程幾乎是透明的. 了解Android的朋友,一定知道Android四大組件,但對於進程可能會相對較陌生. 一個進程裡面可以跑多個app(通過share uid的方式), 一個app也可以跑在多個進程裡(通過配置Android:process屬性).

再進一步進程是如何創建的, 可能很多人不知道fork的存在. 在我的文章理解Android進程創建流程 集中一點詳細介紹了Process.start的過程是如何一步步創建進程.本文則是從另個角度來全局性講解Android進程啟動全過程所涉及的根脈, 先來看看AMS.startProcessLocked方法.

二. 四大組件與進程

2.1 startProcessLocked

ActivityManagerService.java關於啟動進程有4個同名不同參數的重載方法, 為了便於說明,以下4個方法依次記為1(a),1(b)2(a)2(b) :

//方法 1(a)
final ProcessRecord startProcessLocked(
    String processName, ApplicationInfo info, boolean knownToBeDead,
    int intentFlags, String hostingType, ComponentName hostingName,
    boolean allowWhileBooting, boolean isolated, boolean keepIfLarge)

//方法 1(b)
final ProcessRecord startProcessLocked(
    String processName, ApplicationInfo info, boolean knownToBeDead,
    int intentFlags, String hostingType, ComponentName hostingName,
    boolean allowWhileBooting, boolean isolated, int isolatedUid,
    boolean keepIfLarge, String abiOverride, String entryPoint,
    String[] entryPointArgs, Runnable crashHandler)

//方法 2(a)
private final void startProcessLocked(
    ProcessRecord app, String hostingType, String hostingNameStr)

//方法 2(b)
private final void startProcessLocked(
    ProcessRecord app, String hostingType, String hostingNameStr,
    String abiOverride, String entryPoint, String[] entryPointArgs)

1(a) ==> 1(b): 方法1(a)將isolatedUid=0,其他參數賦值為null,再調用給1(b)

final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        String hostingType, ComponentName hostingName, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
    return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
            hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
            null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
            null /* crashHandler */);
}

2(a) ==> 2(b): 方法2(a)將其他3個參數abiOverride,entryPoint, entryPointArgs賦值為null,再調用給2(b)

private final void startProcessLocked(ProcessRecord app,
        String hostingType, String hostingNameStr) {
    startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */,
            null /* entryPoint */, null /* entryPointArgs */);
}

小結:

  • 1(a),1(b)的第一個參數為String類型的進程名processName,
  • 2(a), 2(b)的第一個參數為ProcessRecord類型進程記錄信息ProcessRecord;
  • 1系列的方法最終調用到2系列的方法;

2.2 四大組件與進程

Activity, Service, ContentProvider, BroadcastReceiver這四大組件,在啟動的過程,當其所承載的進程不存在時需要先創建進程. 這個創建進程的過程是調用前面講到的startProcessLocked方法1(a) . 調用流程: 1(a) => 1(b) ==> 2(b). 下面再簡單說說這4大組件與進程創建是在何時需要創建的.

2.2.1 Activity

啟動Activity過程: 調用startActivity,該方法經過層層調用,最終會調用ActivityStackSupervisor.java中的startSpecificActivityLocked,當activity所屬進程還沒啟動的情況下,則需要創建相應的進程.

[-> ActivityStackSupervisor.java]

void startSpecificActivityLocked(...) {
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);
    if (app != null && app.thread != null) {
        ...  //進程已創建的case
        return
    }
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
}

2.2.2 Service

啟動服務過程: 調用startService,該方法經過層層調用,最終會調用ActiveServices.java中的bringUpServiceLocked,當Service進程沒有啟動的情況(app==null), 則需要創建相應的進程. 更多關於Service, 見startService流程分析

[-> ActiveServices.java]

private final String bringUpServiceLocked(...){
    ...
    ProcessRecord app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
    if (app == null) {
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                "service", r.name, false, isolated, false)) == null) {
            ...
        }
    }
    ...
}

2.2.3 ContentProvider

ContentProvider處理過程: 調用ContentResolver.query該方法經過層層調用, 最終會調用到AMS.java中的getContentProviderImpl,當ContentProvider所對應進程不存在,則需要創建新進程. 更多關於ContentProvider,見理解ContentProvider原理(一)

[-> AMS.java]

private final ContentProviderHolder getContentProviderImpl(...) {
    ...
    ProcessRecord proc = getProcessRecordLocked(cpi.processName, cpr.appInfo.uid, false);
    if (proc != null && proc.thread != null) {
        ...  //進程已創建的case
    } else {
        proc = startProcessLocked(cpi.processName,
                    cpr.appInfo, false, 0, "content provider",
                    new ComponentName(cpi.applicationInfo.packageName,cpi.name),
                    false, false, false);
    }
    ...
}

2.2.4 Broadcast

廣播處理過程: 調用sendBroadcast,該方法經過層層調用, 最終會調用到BroadcastQueue.java中的processNextBroadcast,當BroadcastReceiver所對應的進程尚未啟動,則創建相應進程. 更多關於broadcast, 見Android Broadcast廣播機制分析.

[-> BroadcastQueue.java]

final void processNextBroadcast(boolean fromMsg) {
    ...
    ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
        info.activityInfo.applicationInfo.uid, false);
    if (app != null && app.thread != null) {
        ...  //進程已創建的case
        return
    }

    if ((r.curApp=mService.startProcessLocked(targetProcess,
            info.activityInfo.applicationInfo, true,
            r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
            "broadcast", r.curComponent,
            (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                    == null) {
        ...
    }
    ...
}

2.3 小節

Activity, Service, ContentProvider, BroadcastReceiver這四大組件在啟動時,當所承載的進程不存在時,都需要創建. 進程的創建過程交由系統進程system_server來完成的.

app_process_ipc

簡稱:

  • ATP: ApplicationThreadProxy
  • AT: ApplicationThread (繼承於ApplicationThreadNative)
  • AMP: ActivityManagerProxy
  • AMS: ActivityManagerService (繼承於ActivityManagerNative)

圖解:

  1. system_server進程中調用startProcessLocked方法,該方法最終通過socket方式,將需要創建新進程的消息告知Zygote進程,並阻塞等待Socket返回新創建進程的pid;
  2. Zygote進程接收到system_server發送過來的消息, 則通過fork的方法,將zygote自身進程復制生成新的進程,並將ActivityThread相關的資源加載到新進程app process,這個進程可能是用於承載activity等組件;
  3. 創建完新進程後fork返回兩次, 在新進程app process向servicemanager查詢system_server進程中binder服務端AMS,獲取相對應的Client端,也就是AMP. 有了這一對binder c/s對, 那麼app process便可以通過binder向跨進程system_server發送請求,即attachApplication()
  4. system_server進程接收到相應binder操作後,經過多次調用,利用ATP向app process發送binder請求, 即bindApplication.

system_server擁有ATP/AMS, 每一個新創建的進程都會有一個相應的AT/AMS,從而可以跨進程 進行相互通信. 這便是進程創建過程的完整生態鏈.

四大組件的進程創建時機:

組件 創建方法 Activity ASS.startSpecificActivityLocked() Service ActiveServices.bringUpServiceLocked() ContentProvider AMS.getContentProviderImpl() Broadcast BroadcastQueue.processNextBroadcast()

三. 進程啟動全過程

前面剛已介紹四大組件的創建進程的過程是調用1(a) startProcessLocked方法,該方法會再調用1(b)方法. 接下來從該方法開始往下講述.

3.1 AMS.startProcessLocked

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
        boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
        boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
        String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
    long startTime = SystemClock.elapsedRealtime();
    ProcessRecord app;
    if (!isolated) {
        //根據進程名和uid檢查相應的ProcessRecord
        app = getProcessRecordLocked(processName, info.uid, keepIfLarge);

        if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
            //如果當前處於後台進程,檢查當前進程是否處於bad進程列表
            if (mBadProcesses.get(info.processName, info.uid) != null) {
                return null;
            }
        } else {
            //當用戶明確地啟動進程,則清空crash次數,以保證其不處於bad進程直到下次再彈出crash對話框。
            mProcessCrashTimes.remove(info.processName, info.uid);
            if (mBadProcesses.get(info.processName, info.uid) != null) {
                mBadProcesses.remove(info.processName, info.uid);
                if (app != null) {
                    app.bad = false;
                }
            }
        }
    } else {
        //對於孤立進程,無法再利用已存在的進程
        app = null;
    }

    //當存在ProcessRecord,且已分配pid(正在啟動或者已經啟動),
    // 且caller並不認為該進程已死亡或者沒有thread對象attached到該進程.則不應該清理該進程
    if (app != null && app.pid > 0) {
        if (!knownToBeDead || app.thread == null) {
            //如果這是進程中新package,則添加到列表
            app.addPackage(info.packageName, info.versionCode, mProcessStats);
            return app;
        }
        //當ProcessRecord已經被attached到先前的一個進程,則殺死並清理該進程
        killProcessGroup(app.info.uid, app.pid);
        handleAppDiedLocked(app, true, true);
    }

    String hostingNameStr = hostingName != null? hostingName.flattenToShortString() : null;
    if (app == null) {
        // 創建新的Process Record對象
        app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
        if (app == null) {
            return null;
        }
        app.crashHandler = crashHandler;
    } else {
        //如果這是進程中新package,則添加到列表
        app.addPackage(info.packageName, info.versionCode, mProcessStats);
    }
    //當系統未准備完畢,則將當前進程加入到mProcessesOnHold
    if (!mProcessesReady && !isAllowedWhileBooting(info) && !allowWhileBooting) {
        if (!mProcessesOnHold.contains(app)) {
            mProcessesOnHold.add(app);
        }
        return app;
    }
    // 啟動進程【見小節3.2】
    startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
    return (app.pid != 0) ? app : null;
}

主要功能:

  • 對於非isolated進程,則根據進程名和uid來查詢相應的ProcessRecord結構體. 如果當前進程處於後台且當前進程處於mBadProcesses列表,則直接返回;否則清空crash次數,以保證其不處於bad進程直到下次再彈出crash對話框。
  • 當存在ProcessRecord,且已分配pid(正在啟動或者已經啟動)的情況下
    • 當caller並不認為該進程已死亡或者沒有thread對象attached到該進程.則不應該清理該進程,則直接返回;
    • 否則殺死並清理該進程;
  • 當ProcessRecord為空則新建一個,當創建失敗則直接返回;
  • 當系統未准備完畢,則將當前進程加入到mProcessesOnHold, 並直接返回;
  • 最後啟動新進程,其中參數含義:
    • hostingType可取值為”activity”,”service”,”broadcast”,”content provider”;
    • hostingNameStr數據類型為ComponentName,代表的是具體相對應的組件名.

另外, 進程的uid是在進程真正創建之前調用newProcessRecordLocked方法來獲取的uid, 這裡會考慮是否為isolated的情況.

3.2 AMS.startProcessLocked

private final void startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
    long startTime = SystemClock.elapsedRealtime();
    //當app的pid大於0且不是當前進程的pid,則從mPidsSelfLocked中移除該app.pid
    if (app.pid > 0 && app.pid != MY_PID) {
        synchronized (mPidsSelfLocked) {
            mPidsSelfLocked.remove(app.pid);
            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
        }
        app.setPid(0);
    }
    //從mProcessesOnHold移除該app
    mProcessesOnHold.remove(app);
    updateCpuStats(); //更新cpu統計信息
    try {
        try {
            if (AppGlobals.getPackageManager().isPackageFrozen(app.info.packageName)) {
                //當前package已被凍結,則拋出異常
                throw new RuntimeException("Package " + app.info.packageName + " is frozen!");
            }
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
        int uid = app.uid;
        int[] gids = null;
        int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
        if (!app.isolated) {
            int[] permGids = null;
            try {
                //通過Package Manager獲取gids
                final IPackageManager pm = AppGlobals.getPackageManager();
                permGids = pm.getPackageGids(app.info.packageName, app.userId);
                MountServiceInternal mountServiceInternal = LocalServices.getService(
                        MountServiceInternal.class);
                mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
                        app.info.packageName);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }

            //添加共享app和gids,用於app直接共享資源
            if (ArrayUtils.isEmpty(permGids)) {
                gids = new int[2];
            } else {
                gids = new int[permGids.length + 2];
                System.arraycopy(permGids, 0, gids, 2, permGids.length);
            }
            gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
            gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
        }

        //根據不同參數,設置相應的debugFlags
        ...

        app.gids = gids;
        app.requiredAbi = requiredAbi;
        app.instructionSet = instructionSet;

        boolean isActivityProcess = (entryPoint == null);
        if (entryPoint == null) entryPoint = "android.app.ActivityThread";
        //請求Zygote創建新進程[見3.3]
        Process.ProcessStartResult startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
                app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                app.info.dataDir, entryPointArgs);

        ...
        if (app.persistent) {
            Watchdog.getInstance().processStarted(app.processName, startResult.pid);
        }
        //重置ProcessRecord的成員變量
        app.setPid(startResult.pid);
        app.usingWrapper = startResult.usingWrapper;
        app.removed = false;
        app.killed = false;
        app.killedByAm = false;

        //將新創建的進程加入到mPidsSelfLocked
        synchronized (mPidsSelfLocked) {
            this.mPidsSelfLocked.put(startResult.pid, app);
            if (isActivityProcess) {
                Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                msg.obj = app;
                //延遲發送消息PROC_START_TIMEOUT_MSG
                mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                        ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
            }
        }
    } catch (RuntimeException e) {
        app.setPid(0); //進程創建失敗,則重置pid
    }
}
  • 根據不同參數,設置相應的debugFlags,比如在AndroidManifest.xml中設置androidd:debuggable為true,代表app運行在debug模式,則增加debugger標識以及開啟JNI check功能
  • 調用Process.start來創建新進程;
  • 重置ProcessRecord的成員變量, 一般情況下超時10s後發送PROC_START_TIMEOUT_MSG的handler消息;

關於Process.start()是通過socket通信告知Zygote創建fork子進程,創建新進程後將ActivityThread類加載到新進程,並調用ActivityThread.main()方法。詳細過程見理解Android進程創建流程,接下來進入AT.main方法.

3.3 ActivityThread.main

[-> ActivityThread.java]

public static void main(String[] args) {
    //性能統計默認是關閉的
    SamplingProfilerIntegration.start();
    //將當前進程所在userId賦值給sCurrentUser
    Environment.initForCurrentUser();

    EventLogger.setReporter(new EventLoggingReporter());
    AndroidKeyStoreProvider.install();

    //確保可信任的CA證書存放在正確的位置
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    Process.setArgV0("<pre-initialized>");

    //創建主線程的Looper對象, 該Looper是不運行退出
    Looper.prepareMainLooper();

    //創建ActivityThread對象
    ActivityThread thread = new ActivityThread();

    //建立Binder通道 【見流程3.4】
    thread.attach(false);
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    // 當設置為true時,可打開消息隊列的debug log信息
    if (false) {
        Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
    }
    Looper.loop(); //消息循環運行
    throw new RuntimeException("Main thread loop unexpectedly exited");
}
  • 創建主線程的Looper對象: 該Looper是不運行退出. 也就是說主線程的Looper是在進程創建完成時自動創建完成,如果子線程也需要創建handler通信過程,那麼就需要手動創建Looper對象,並且每個線程只能創建一次.
  • 創建ActivityThread對象thread = new ActivityThread(): 該過程會初始化幾個很重要的變量:
    • mAppThread = new ApplicationThread()
    • mLooper = Looper.myLooper()
    • mH = new H(), H繼承於Handler;用於處理組件的生命周期.
  • attach過程是當前主線程向system_server進程通信的過程, 將thread信息告知AMS.接下來還會進一步說明該過程.
  • sMainThreadHandler通過getHandler(),獲取的對象便是mH,這就是主線程的handler對象.

之後主線程調用Looper.loop(),進入消息循環狀態, 當沒有消息時主線程進入休眠狀態, 一旦有消息到來則喚醒主線程並執行相關操作.

3.4. ActivityThread.attach

[-> ActivityThread.java]

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
         //開啟虛擬機的jit即時編譯功能
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                ensureJitEnabled();
            }
        });
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId());

        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        //創建ActivityManagerProxy對象
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            //調用基於IActivityManager接口的Binder通道【見流程3.5】
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
        }

        //觀察是否快接近heap的上限
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return;
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    mSomeActivitiesChanged = false;
                    try {
                        //當已用內存超過最大內存的3/4,則請求釋放內存空間
                        mgr.releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                    }
                }
            }
        });
    } else {
        ...
    }
    //添加dropbox日志到libcore
    DropBox.setReporter(new DropBoxReporter());

    //添加Config回調接口
    ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            synchronized (mResourcesManager) {
                if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
                    if (mPendingConfiguration == null ||
                            mPendingConfiguration.isOtherSeqNewer(newConfig)) {
                        mPendingConfiguration = newConfig;
                        sendMessage(H.CONFIGURATION_CHANGED, newConfig);
                    }
                }
            }
        }
        @Override
        public void onLowMemory() {
        }
        @Override
        public void onTrimMemory(int level) {
        }
    });
}

對於非系統attach的處理流程:

  • 創建線程來開啟虛擬機的jit即時編譯;
  • 通過binder, 調用到AMS.attachApplication, 其參數mAppThread的數據類型為ApplicationThread
  • 觀察是否快接近heap的上限,當已用內存超過最大內存的3/4,則請求釋放內存空間
  • 添加dropbox日志到libcore
  • 添加Config回調接口

3.5 AMP.attachApplication

[-> ActivityManagerProxy.java]

public void attachApplication(IApplicationThread app) throws RemoteException
{
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(app.asBinder());
    mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0); //【見流程3.6】
    reply.readException();
    data.recycle();
    reply.recycle();
}

此處 descriptor = “android.app.IActivityManager”

3.6 AMN.onTransact

[-> ActivityManagerNative.java]

public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
    switch (code) {
    ...
     case ATTACH_APPLICATION_TRANSACTION: {
        data.enforceInterface(IActivityManager.descriptor);
        //獲取ApplicationThread的binder代理類 ApplicationThreadProxy
        IApplicationThread app = ApplicationThreadNative.asInterface(
                data.readStrongBinder());
        if (app != null) {
            attachApplication(app); //此處是ActivityManagerService類中的方法 【見流程3.7】
        }
        reply.writeNoException();
        return true;
    }
    }
}

3.7 AMS.attachApplication

[-> ActivityManagerService.java]

public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid); // 【見流程3.8】
        Binder.restoreCallingIdentity(origId);
    }
}

此處的thread便是ApplicationThreadProxy對象,用於跟前面通過Process.start()所創建的進程中ApplicationThread對象進行通信.

3.8 AMS.attachApplicationLocked

[-> ActivityManagerService.java]

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {
    ProcessRecord app;
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            app = mPidsSelfLocked.get(pid); // 根據pid獲取ProcessRecord
        }
    } else {
        app = null;
    }
    if (app == null) {
        if (pid > 0 && pid != MY_PID) {
            //ProcessRecord為空,則殺掉該進程
            Process.killProcessQuiet(pid);
        } else {
            //退出新建進程的Looper
            thread.scheduleExit();
        }
        return false;
    }

    //還剛進入attach過程,此時thread應該為null,若不為null則表示該app附到上一個進程,則立刻清空
    if (app.thread != null) {
        handleAppDiedLocked(app, true, true);
    }

    final String processName = app.processName;
    try {
        //綁定死亡通知
        AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName); //重新啟動進程
        return false;
    }

    //重置進程信息
    app.makeActive(thread, mProcessStats); //執行完該語句,則app.thread便不再為空
    app.curAdj = app.setAdj = -100;
    app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
    app.forcingToForeground = null;
    updateProcessForegroundLocked(app, false, false);
    app.hasShownUi = false;
    app.debugging = false;
    app.cached = false;
    app.killedByAm = false;
    mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); //移除進程啟動超時的消息

    //系統處於ready狀態或者該app為FLAG_PERSISTENT進程,則為true
    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
    List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;

    //app進程存在正在啟動中的provider,則超時10s後發送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息
    if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
        Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
        msg.obj = app;
        mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
    }

    try {
        ...
        ensurePackageDexOpt(app.instrumentationInfo != null
                ? app.instrumentationInfo.packageName
                : app.info.packageName);

        ApplicationInfo appInfo = app.instrumentationInfo != null
                ? app.instrumentationInfo : app.info;
        ...
        // 綁定應用 [見流程3.9]
        thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(mConfiguration), app.compat,
                getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked());
        //更新進程LRU隊列
        updateLruProcessLocked(app, false, null);
        app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
    } catch (Exception e) {
        app.resetPackageList(mProcessStats);
        app.unlinkDeathRecipient();
        //每當bind操作失敗,則重啟啟動進程, 此處有可能會導致進程無限重啟
        startProcessLocked(app, "bind fail", processName);
        return false;
    }

    mPersistentStartingProcesses.remove(app);
    mProcessesOnHold.remove(app);
    boolean badApp = false;
    boolean didSomething = false;

    //Activity: 檢查最頂層可見的Activity是否等待在該進程中運行
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            badApp = true;
        }
    }

    //Service: 尋找所有需要在該進程中運行的服務
    if (!badApp) {
        try {
            didSomething |= mServices.attachApplicationLocked(app, processName);
        } catch (Exception e) {
            badApp = true;
        }
    }

    //Broadcast: 檢查是否在這個進程中有下一個廣播接收者
    if (!badApp && isPendingBroadcastProcessLocked(pid)) {
        try {
            didSomething |= sendPendingBroadcastsLocked(app);
        } catch (Exception e) {
            badApp = true;
        }
    }
    //檢查是否在這個進程中有下一個backup代理
    if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
        ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
        try {
            thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
                    compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
                    mBackupTarget.backupMode);
        } catch (Exception e) {
            badApp = true;
        }
    }
    if (badApp) { //殺掉bad應用
        app.kill("error during init", true);
        handleAppDiedLocked(app, false, true);
        return false;
    }
    if (!didSomething) {
        updateOomAdjLocked(); //更新adj的值
    }
    return true;
}
  1. 根據pid從mPidsSelfLocked中查詢到相應的ProcessRecord對象app;
  2. 當app==null,意味著本次創建的進程不存在, 則直接返回.
  3. 還剛進入attach過程,此時thread應該為null,若不為null則表示該app附到上一個進程,則調用handleAppDiedLocked清理.
  4. 綁定死亡通知,當進程pid死亡時會通過binder死亡回調,來通知system_server進程死亡的消息;
  5. 重置ProcessRecord進程信息, 此時app.thread也賦予了新值,便不再為空.
  6. app進程存在正在啟動中的provider,則超時10s後發送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息
  7. 調用thread.bindApplication綁定應用進程, 後面再進一步說明
  8. 處理Provider, Activity, Service, Broadcast相應流程

下面,再來說說thread.bindApplication的過程.

3.9 ATP.bindApplication

[-> ApplicationThreadNative.java ::ApplicationThreadProxy]

class ApplicationThreadProxy implements IApplicationThread {
    ...
    public final void bindApplication(String packageName, ApplicationInfo info,
            List<ProviderInfo> providers, ComponentName testName, ProfilerInfo profilerInfo,
            Bundle testArgs, IInstrumentationWatcher testWatcher,
            IUiAutomationConnection uiAutomationConnection, int debugMode,
            boolean openGlTrace, boolean restrictedBackupMode, boolean persistent,
            Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
            Bundle coreSettings) throws RemoteException {
        Parcel data = Parcel.obtain();
        data.writeInterfaceToken(IApplicationThread.descriptor);
        data.writeString(packageName);
        info.writeToParcel(data, 0);
        data.writeTypedList(providers);
        if (testName == null) {
            data.writeInt(0);
        } else {
            data.writeInt(1);
            testName.writeToParcel(data, 0);
        }
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        data.writeBundle(testArgs);
        data.writeStrongInterface(testWatcher);
        data.writeStrongInterface(uiAutomationConnection);
        data.writeInt(debugMode);
        data.writeInt(openGlTrace ? 1 : 0);
        data.writeInt(restrictedBackupMode ? 1 : 0);
        data.writeInt(persistent ? 1 : 0);
        config.writeToParcel(data, 0);
        compatInfo.writeToParcel(data, 0);
        data.writeMap(services);
        data.writeBundle(coreSettings);
        mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
                IBinder.FLAG_ONEWAY);
        data.recycle();
    }
    ...
}

ATP經過binder ipc傳遞到ATN的onTransact過程.

3.10 ATN.onTransact

[-> ApplicationThreadNative.java]

public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
    switch (code) {
    ...
    case BIND_APPLICATION_TRANSACTION:
    {
        data.enforceInterface(IApplicationThread.descriptor);
        String packageName = data.readString();
        ApplicationInfo info =
            ApplicationInfo.CREATOR.createFromParcel(data);
        List<ProviderInfo> providers =
            data.createTypedArrayList(ProviderInfo.CREATOR);
        ComponentName testName = (data.readInt() != 0)
            ? new ComponentName(data) : null;
        ProfilerInfo profilerInfo = data.readInt() != 0
                ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
        Bundle testArgs = data.readBundle();
        IBinder binder = data.readStrongBinder();
        IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder);
        binder = data.readStrongBinder();
        IUiAutomationConnection uiAutomationConnection =
                IUiAutomationConnection.Stub.asInterface(binder);
        int testMode = data.readInt();
        boolean openGlTrace = data.readInt() != 0;
        boolean restrictedBackupMode = (data.readInt() != 0);
        boolean persistent = (data.readInt() != 0);
        Configuration config = Configuration.CREATOR.createFromParcel(data);
        CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
        HashMap<String, IBinder> services = data.readHashMap(null);
        Bundle coreSettings = data.readBundle();
        //[見流程3.11]
        bindApplication(packageName, info, providers, testName, profilerInfo, testArgs,
                testWatcher, uiAutomationConnection, testMode, openGlTrace,
                restrictedBackupMode, persistent, config, compatInfo, services, coreSettings);
        return true;
    }
    ...
}

3.11 AT.bindApplication

[-> ActivityThread.java ::ApplicationThread]

public final void bindApplication(String processName, ApplicationInfo appInfo,
        List<ProviderInfo> providers, ComponentName instrumentationName,
        ProfilerInfo profilerInfo, Bundle instrumentationArgs,
        IInstrumentationWatcher instrumentationWatcher,
        IUiAutomationConnection instrumentationUiConnection, int debugMode,
        boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
        Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
        Bundle coreSettings) {

    if (services != null) {
        //將services緩存起來, 減少binder檢索服務的次數
        ServiceManager.initServiceCache(services);
    }

    //發送消息H.SET_CORE_SETTINGS
    setCoreSettings(coreSettings);

    IPackageManager pm = getPackageManager();
    android.content.pm.PackageInfo pi = null;
    try {
        pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId());
    } catch (RemoteException e) {
    }
    if (pi != null) {
        boolean sharedUserIdSet = (pi.sharedUserId != null);
        boolean processNameNotDefault = (pi.applicationInfo != null &&
         !appInfo.packageName.equals(pi.applicationInfo.processName));
        boolean sharable = (sharedUserIdSet || processNameNotDefault);

        if (!sharable) {
            VMRuntime.registerAppInfo(appInfo.packageName, appInfo.dataDir,
                                    appInfo.processName);
        }
    }

    //初始化AppBindData, 再發送消息H.BIND_APPLICATION
    AppBindData data = new AppBindData();
    data.processName = processName;
    data.appInfo = appInfo;
    data.providers = providers;
    data.instrumentationName = instrumentationName;
    data.instrumentationArgs = instrumentationArgs;
    data.instrumentationWatcher = instrumentationWatcher;
    data.instrumentationUiAutomationConnection = instrumentationUiConnection;
    data.debugMode = debugMode;
    data.enableOpenGlTrace = enableOpenGlTrace;
    data.restrictedBackupMode = isRestrictedBackupMode;
    data.persistent = persistent;
    data.config = config;
    data.compatInfo = compatInfo;
    data.initProfilerInfo = profilerInfo;
    sendMessage(H.BIND_APPLICATION, data);
}

其中setCoreSettings()過程就是調用sendMessage(H.SET_CORE_SETTINGS, coreSettings) 來向主線程發送SET_CORE_SETTINGS消息.bindApplication方法的主要功能是依次向主線程發送消息H.SET_CORE_SETTINGSH.BIND_APPLICATION. 接下來再來說說這兩個消息的處理過程

3.12 H.SET_CORE_SETTINGS

[-> ActivityThread.java ::H]

當主線程收到H.SET_CORE_SETTINGS,則調用handleSetCoreSettings

private void handleSetCoreSettings(Bundle coreSettings) {
    synchronized (mResourcesManager) {
        mCoreSettings = coreSettings;
    }
    onCoreSettingsChange();
}

private void onCoreSettingsChange() {
    boolean debugViewAttributes = mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
    if (debugViewAttributes != View.mDebugViewAttributes) {
        View.mDebugViewAttributes = debugViewAttributes;

        // 由於發生改變, 請求所有的activities重啟啟動
        for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
            requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false);
        }
    }
}

3.13 H.BIND_APPLICATION

[-> ActivityThread.java ::H]

當主線程收到H.BIND_APPLICATION,則調用handleBindApplication

private void handleBindApplication(AppBindData data) {

    mBoundApplication = data;
    mConfiguration = new Configuration(data.config);
    mCompatConfiguration = new Configuration(data.config);

    ...

    //設置進程名, 也就是說進程名是在進程真正創建以後的BIND_APPLICATION過程中才取名
    Process.setArgV0(data.processName);
    android.ddm.DdmHandleAppName.setAppName(data.processName, UserHandle.myUserId());

    if (data.persistent) {
        //低內存設備, persistent進程不采用硬件加速繪制,以節省內存使用量
        if (!ActivityManager.isHighEndGfx()) {
            HardwareRenderer.disable(false);
        }
    }

    //重置時區
    TimeZone.setDefault(null);
    Locale.setDefault(data.config.locale);

    //更新系統配置
    mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
    mCurDefaultDisplayDpi = data.config.densityDpi;
    applyCompatConfiguration(mCurDefaultDisplayDpi);

    data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
    ...

    // 創建ContextImpl上下文
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
    if (!Process.isIsolated()) {
        final File cacheDir = appContext.getCacheDir();
        if (cacheDir != null) {
            System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
        }

        //用於存儲產生/編譯的圖形代碼
        final File codeCacheDir = appContext.getCodeCacheDir();
        if (codeCacheDir != null) {
            setupGraphicsSupport(data.info, codeCacheDir);
        }
    }

    final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
    DateFormat.set24HourTimePref(is24Hr);

    View.mDebugViewAttributes =  mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
    ...

    //當處於調試模式,則運行應用生成systrace信息
    boolean appTracingAllowed = (data.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0;
    Trace.setAppTracingAllowed(appTracingAllowed);

    //初始化 默認的http代理
    IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
    if (b != null) {
        IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
        final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
        Proxy.setHttpProxySystemProperty(proxyInfo);
    }

    if (data.instrumentationName != null) {
        InstrumentationInfo ii = null;
        ii = appContext.getPackageManager().getInstrumentationInfo(data.instrumentationName, 0);

        mInstrumentationPackageName = ii.packageName;
        mInstrumentationAppDir = ii.sourceDir;
        mInstrumentationSplitAppDirs = ii.splitSourceDirs;
        mInstrumentationLibDir = ii.nativeLibraryDir;
        mInstrumentedAppDir = data.info.getAppDir();
        mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
        mInstrumentedLibDir = data.info.getLibDir();

        ApplicationInfo instrApp = new ApplicationInfo();
        instrApp.packageName = ii.packageName;
        instrApp.sourceDir = ii.sourceDir;
        instrApp.publicSourceDir = ii.publicSourceDir;
        instrApp.splitSourceDirs = ii.splitSourceDirs;
        instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs;
        instrApp.dataDir = ii.dataDir;
        instrApp.nativeLibraryDir = ii.nativeLibraryDir;
        LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                appContext.getClassLoader(), false, true, false);
        ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

        java.lang.ClassLoader cl = instrContext.getClassLoader();
        mInstrumentation = (Instrumentation)cl.loadClass(data.instrumentationName.getClassName()).newInstance();

        mInstrumentation.init(this, instrContext, appContext,
               new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
               data.instrumentationUiAutomationConnection);
        ...
    } else {
        mInstrumentation = new Instrumentation();
    }

    //FLAG_LARGE_HEAP則清除內存增長上限
    if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
        dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
    } else {
        dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
    }

    try {
        // 通過反射,創建目標應用Application對象,即在AndroidManifest.xml文件定義的應用名
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;

        if (!data.restrictedBackupMode) {
            List<ProviderInfo> providers = data.providers;
            if (providers != null) {
                installContentProviders(app, providers);
                mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
            }
        }

        mInstrumentation.onCreate(data.instrumentationArgs);
        //調用Application.onCreate()回調方法.
        mInstrumentation.callApplicationOnCreate(app);

    } finally {
        StrictMode.setThreadPolicy(savedPolicy);
    }
}

小節: 到此進程啟動的全過程基本介紹完, 那接下來程序該往哪執行呢, 那就是要繼續看[見流程3.8] AMS.attachApplicationLocked.從[3.9 ~ 3.13] 只是介紹了bindApplication過程, 該方法之後便是組件啟動相關的內容,本文主要將進程相關內容, 組件的內容後續還會再進一步介紹.

四. 總結

本文首先介紹AMS的4個同名不同參數的方法startProcessLocked; 緊接著講述了四大組件與進程的關系, Activity, Service, ContentProvider, BroadcastReceiver這四大組件,在啟動的過程,當其所承載的進程不存在時需要先創建進程. 再然後進入重點以startProcessLocked以引線一路講解整個過程所遇到的核心方法. 在整個過程中有新創建的進程與system_server進程之間的交互過程 是通過binder進行通信的, 這裡有兩條binder通道分別為AMP/AMN 和 ATP/ATN.

start_process

上圖便是一次完整的進程創建過程,app的任何組件需要有一個承載其運行的容器,那就是進程, 那麼進程的創建過程都是由系統進程system_server通過socket向zygote進程來請求fork()新進程, 當創建出來的app process與system_server進程之間的通信便是通過binder IPC機制.

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