Application創建流程分析

前言

要想啓動一個應用程序,首先要保證這個應用程所需要的應用程序進程已經創建啓動。AMS在啓動應用程序時,會檢查這個應用程序需要的應用程序進程是否存在,不存在就會請求Zygote孵化器進程來啓動需要的應用程序進程。因此應用程序進程啓動過程可以概括爲兩個部分:

  • AMS發送啓動應用程序進程請求
  • Zygote接收請求並創建應用程序進程

關於這部分的具體流程分析可參考《Android進階解密》第二章內容。本文重點分析Zygote創建應用程序進程走到ActivityThread的main方法後,創建Application的流程。

進入ActivityThread的main方法,需要關注的核心代碼如下:

frameworks/base/core/java/android/app/ActivityThread.java

public static void main(String[] args) {
    ...

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    // 需要關注的代碼
    thread.attach(false);
    ...
    Looper.loop();
	...
}

接下來進入attach方法,代碼很多,但是需要重點關注的就這幾行:

private void attach(boolean system) {
    ...
    // 註釋1
    final IActivityManager mgr = ActivityManager.getService();
    try {
        // 註釋2
        mgr.attachApplication(mAppThread);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
	...
}

如果對Binder機制稍有了解,你就會知道,註釋1處調用ActivityManager的getService方法來獲取AMS的代理對象,接着調用AMS的attachApplication方法。這裏與Android8.0之前的代碼邏輯有些不同,Android8.0之前是通過ActivityManagerNative的getDefault來獲取AMS的代理對象的,現在這個邏輯封裝到了ActivityManager中而不是ActivityManagerNative中。這裏先查看ActivityManager的getService方法:

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
                // 註釋1
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                // 註釋2
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am;
            }
        };

在註釋1處獲取IBinder類型的AMS引用(binder對象),接着在註釋2處將它轉換成IActivityManager類型的對象(也就是AMS的代理對象),這段代碼採用的AIDL,IActivityManager.java文件是由AIDL工具在編譯時自動生成的,IActivityManager.aidl的文件路徑爲frameworks/base/core/java\android/app/IActivityMananger.aidl。要實現跨進程通信,服務端也就是AMS只需要繼承IActivityManager.Stub類並實現相應的方法就可以了。Android8.0之前並沒有採用AIDL,用AMS的代理對象ActivityManagerProxy來與AMS進行通信,Android8.0去除了ActivityManagerNative的內部類ActivityManagerProxy,代替它的是IActivityManager,它是AMS在本地的代理。言歸正傳,回到attach方法,接下來進入AMS的attachApplication方法(跨進程通信,AMS在SystemServer進程)

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

@Override
public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        // 註釋1
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}

接下來進入註釋1處的attachApplicationLocked方法:

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {

    // Find the application record that is being attached...  either via
    // the pid if we are running in multiple processes, or just pull the
    // next app record if we are emulating process with anonymous threads.
    // 用於描述一個應用程序進程(記錄應用程序進程的相關信息)
    ProcessRecord app;
    ...
        if (app.instr != null) {
            thread.bindApplication(processName, appInfo, providers,
                    app.instr.mClass,
                    profilerInfo, app.instr.mArguments,
                    app.instr.mWatcher,
                    app.instr.mUiAutomationConnection, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial);
        } else {
            thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                    null, null, null, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial);
        }
    ...

    return true;
}

AMS負責四大組件的啓動、切換、調度以及應用程序進程的管理,是Android中最爲核心的服務,參與了應用程序的啓動管理。這裏省去了大量的檢查和初始化的代碼,保存要創建應用程序進程的相關信息等操作,也就是說通過ProcessRecord即應用程序進程信息的相關判斷,thread是IApplicationThread類型的,此處代表的是IApplicationThread的代理對象,調用bindApplication方法,ApplicationThread繼承IApplicationThread.Stub,此處又是Binder機制的跨進程通信,接下來進入ApplicationThread的bindApplication方法,ApplicationThread是ActivityThread的內部類,又從AMS所在的SystemServer系統服務進程回到了應用程序進程。

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

    if (services != null) {
        // Setup the service cache in the ServiceManager
        ServiceManager.initServiceCache(services);
    }

    setCoreSettings(coreSettings);

    AppBindData data = new AppBindData();
    data.processName = processName;
    data.appInfo = appInfo;
    data.providers = providers;
    ......
    // 註釋1
    sendMessage(H.BIND_APPLICATION, data);
}

將應用程序進程的相關信息保存到AppBindData類型的data中,通過sendMessage方法發送消息,交給H類型的Handler處理

private class H extends Handler {
    ...
    public static final int BIND_APPLICATION        = 110;
    ...
    public void handleMessage(Message msg) {
        switch (msg.what) {
            ...
                case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                	//調用ActivityThread的handleBindApplication()方法處理
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
            ...
        }
    }
}

進入H類的handleMessage方法,找到BIND_APPLICATION對應的case,從msg中取出之前保存的AppBindData類型的數據data,交給handleBindApplication方法

 private void handleBindApplication(AppBindData data) {
   // 註釋1 獲取LoadedApk
   data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
   ...
   try {
       // 註釋2
       // 創建一個Application對象     
       Application app = data.info.makeApplication(data.restrictedBackupMode,null);
       mInitialApplication = app;
       try {
          // 註釋3
          // 通過mInstrumentation對象,回調Application的onCreate()方法  
           mInstrumentation.callApplicationOnCreate(app);
       } catch (Exception e) {
            ...
        } finally {
            ...
        }
        ...  
}

先看註釋1處,通過getPackageInfoNoCheck()方法對AppBindData對象的info變量賦值,info變量的類型是LoadedApk,關於LoadedApk,有一個通俗的說法,LoadedApk對象是apk文件在內存中的表示,apk文件的相關信息,比如apk文件中的資源,甚至是代碼裏面的Activity、Service等組件的信息都可以通過此對象獲取,我們來看下getPackageInfoNoCheck()方法的源碼

public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
            CompatibilityInfo compatInfo) {
    return getPackageInfo(ai, compatInfo, null, false, true, false);
}

接着進入getPackageInfo方法:

private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
        ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
        boolean registerPackage) {
        /*
         * 下面這個地方不是很理解,看下面這一行代碼的意思應該是判斷是不是同一個用戶
         * 查了一下,differentUser的值大部分情況下應該都是false
         */
        final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
        synchronized (mResourcesManager) {
            WeakReference<LoadedApk> ref;
            if (differentUser) {
                // Caching not supported across users
                ref = null;
            } else if (includeCode) {
                /*在getPackageInfoNoCheck()方法中調用本方法時,includeCode的值爲true
                 *從緩存中根據應用的報名獲取LoadedApk的弱引用對象
                 */
                ref = mPackages.get(aInfo.packageName);
            } else {
                ref = mResourcePackages.get(aInfo.packageName);
            }
 
            LoadedApk packageInfo = ref != null ? ref.get() : null;
            /*
             * 當獲取的LoadedApk對象爲null時,或者說是放緩存中不存在對應的LoadedApk對象時候
             * 則調用LoadedApk的構造方法,創建一個LoadedApk對象
             */
            if (packageInfo == null || (packageInfo.mResources != null
                    && !packageInfo.mResources.getAssets().isUpToDate())) {            
                ...
               
                packageInfo =
                    new LoadedApk(this, aInfo, compatInfo, baseLoader,
                            securityViolation, includeCode &&
                            (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
 
                ...
                
                if (differentUser) {
                    // Caching not supported across users
                } else if (includeCode) {
                    //把創建的LoadedApk對象放入緩存中
                    mPackages.put(aInfo.packageName,
                            new WeakReference<LoadedApk>(packageInfo));
                } else {
                    mResourcePackages.put(aInfo.packageName,
                            new WeakReference<LoadedApk>(packageInfo));
                }
            }
            return packageInfo;
        }
}

總結一下getPackageInfo()方法的作用就是,從緩存中獲取對應的LoadedApk對象,若緩存中不存在該對象,便去創建一個對象,保存在緩存裏,並return LoadedApk的對象,最終把該對象賦值給handleBindApplication()中的data.info。

我們繼續回到handleBindApplication()方法中的註釋2處,調用data.info也就是LoadedApk對象的makeApplication()方法,創建一個Application對象,我們來看下makeApplication()方法

frameworks/base/core/java/android/app/LoadedApk.java

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        
        //若Application已經創建過,直接return
        if (mApplication != null) {
            return mApplication;
        }
        ...
        Application app = null;
        ...
        try {
            ...
            // 註釋1
            // 獲取一個ContextImpl上下文對象
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            
            // 註釋2             
            // 通過Instrumentation對象的newApplication()方法創建一個Application對象,
            // 創建的這個Application對象也是makeApplication()方法最終return的對象
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            ...
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
        ...
        return app;
}

註釋1處,內部主要還是通過new ContextImpl(xxx)的形式創建ContextImpl對象。再看註釋2處,進入Instrumentation的newApplication方法,顧名思義它的作用就是創建Application

static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
	Application app = (Application)clazz.newInstance();
    app.attach(context);
    return app;
}

該反方最終通過反射的方式創建了一個Application對象,並且調用了Appliction的attach()方法,而attach方法又調用了attachBaseContext方法,現在應該明白爲什麼該方法在Application的onCreate之前調用了。

final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

接下來回到handleBindApplication方法的註釋3處,通過mInstrumentation對象,調用callApplicationOnCreate方法,顧名思義就是去調用執行Application的onCreate()方法

public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }

文章的後半部分主要是從handleBindApplication方法的3處重要邏輯展開的,爲了看得更清晰一點,簡單小結一下:

  • data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); 獲取保存Apk文件信息的LoadedApk對象
  • Application app = data.info.makeApplication(data.restrictedBackupMode,null); 內部通過反射創建Application對象,在這個過程中會調用Application的attachBaseContext方法
  • mInstrumentation.callApplicationOnCreate(app); 通過Instrumentation的callApplicationOnCreate方法執行Application的生命週期方法onCreate
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章