ActivityManagerService啓動流程詳解

ActivityManagerService,簡稱AMS,具備管理Activity行爲、控制activity的生命週期、派發消息事件、內存管理等功能,AMS的另外兩個重要概念是兩大核心功能是WindowManagerService.java和View.java。
分析ActivityManagerService的流程以前須要先下載Android的系統源碼,相關下載能夠參照下面的文章:中國大陸如何下載 Android 源碼java

用戶從Launcher程序點擊應用圖標可啓動應用的入口Activity,Activity啓動時須要多個進程之間的交互,以下圖所示。
這裏寫圖片描述android

其中,AMS進程其實是SystemServer進程,由於AMS只是SystemServer啓動的一個服務而已,運行在SystemServer的某個線程中。數組

具體的,用戶在Launcher程序裏點擊應用圖標時,會通知ActivityManagerService啓動應用的主Activity,ActivityManagerService發現這個應用還未啓動,則會通知Zygote進程執行ActivityThread的main方法。應用進程接下來通知ActivityManagerService應用進程已啓動,ActivityManagerService保存應用進程的一個代理對象,這樣ActivityManagerService能夠經過這個代理對象控制應用進程,而後ActivityManagerService通知應用進程建立主Activity的實例,並執行它的生命週期方法,也就是諸如OnCreadte()等方法。緩存

Launcher啓動

當點擊應用程序圖標後,Launcher 使用一個帶有 Intent.FLAG_ACTIVITY_NEW_TASK flag 的 Intent,調用 startActivity 方法來啓動App。相關源碼以下:網絡

public static Intent makeLaunchIntent(Context context, LauncherActivityInfoCompat info,
            UserHandleCompat user) {
        long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
        return new Intent(Intent.ACTION_MAIN)
            .addCategory(Intent.CATEGORY_LAUNCHER)
            .setComponent(info.getComponentName())
            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
            .putExtra(EXTRA_PROFILE, serialNumber);
    }

當點擊app的圖標時會執行以下的代碼調用流程。數據結構

public void onClick(View v) {
      ...
      Object tag = v.getTag();
      if (tag instanceof ShortcutInfo) {
          onClickAppShortcut(v);
      }
       ...
  }


protected void onClickAppShortcut(final View v) {
...
      // Start activities
      startAppShortcutOrInfoActivity(v);
...
}


void startAppShortcutOrInfoActivity(View v) {
...
        // 獲得launcher提供的啓動這個app主activity的intent
        intent = shortcut.intent;
...
        boolean success = startActivitySafely(v, intent, tag);
...
    }

 boolean startActivitySafely(View v, Intent intent, Object tag) {

  ...  
  success = startActivity(v, intent, tag);
  ...

}


private boolean startActivity(View v, Intent intent, Object tag) {
       intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        ...
        startActivity(intent, optsBundle);
        ...
}

從以上代碼流程可知當Launcher啓動一個app時,會在本身的startActivity()方法中爲Intent中添加一個FLAG_ACTIVITY_NEW_TASK flag,而後調用繼承自Activity的startActivity()方法來進一步啓動app。併發

Activity向AMS發起請求啓動App

Activity啓動Activity的流程以下,具體能夠查看相關的源碼,須要注意的是Android 6.0的實現和8.0版本實現有略微的區別。app

這裏寫圖片描述

下面咱們看一下ActivityThread類,ActivityThread類是Android應用進程的核心類,這個類包含了應用框架中其餘重要的類。其源碼以下:框架

public final class ActivityThread {
........
private ContextImpl mSystemContext;

static IPackageManager sPackageManager;
// 保存該app中全部的Activity
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
// 保存該app中全部的service
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
// 保存該app中全部的provider
final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
        = new ArrayMap<ProviderKey, ProviderClientRecord>();
//管理應用的資源
private final ResourcesManager mResourcesManager;

// 存儲包含代碼,即dex文件的apk文件保存在該變量中
final ArrayMap<String, WeakReference<LoadedApk>> mPackages
        = new ArrayMap<String, WeakReference<LoadedApk>>();
// 不包含代碼,牢牢包含資源的apk放在該變量中
final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages

// 若是app中本身實現了Application的子類,並在清單文件中聲明瞭,那麼該變量就指向本身實現的那個子類對象
Application mInitialApplication;

AppBindData mBoundApplication;

// 用於binder通訊,AMS經過它來調用應用的接口
final ApplicationThread mAppThread = new ApplicationThread();

// 主線程中的Handler
static Handler sMainThreadHandler;  // set once in main()

final Looper mLooper = Looper.myLooper();

// H繼承自Handler,mH用來發送和處理ApplicationThread經過binder接受的AMS請求
final H mH = new H();

.........
}

ActivityThread類中沒有定義數據結構來存儲BroadcastReceiver對象,由於BroadcastReceiver對象生命週期很短暫,屬於調用一次運行一次的類型,所以不須要保存其對象。AppBindData類爲ActivityThread的內部類,定義以下,記錄了與之綁定的app的相關數據。async

static final class AppBindData {
    LoadedApk info;
    String processName;
    ApplicationInfo appInfo;
    List<ProviderInfo> providers;
    ComponentName instrumentationName;
    Bundle instrumentationArgs;
    IInstrumentationWatcher instrumentationWatcher;
    IUiAutomationConnection instrumentationUiAutomationConnection;
    int debugMode;
    boolean enableOpenGlTrace;
    boolean restrictedBackupMode;
    boolean persistent;
    Configuration config;
    CompatibilityInfo compatInfo;

    /** Initial values for {@link Profiler}. */
    ProfilerInfo initProfilerInfo;

    public String toString() {
        return "AppBindData{appInfo=" + appInfo + "}";
    }
}

其中 ApplicationThread類型的變量mAppThread用於AMS所在app的接口,應用進程須要調用AMS提供的功能,而AMS也須要主動調用應用進程以控制應用進程並完成指定操做。ApplicationThread的運做流程以下圖:
這裏寫圖片描述
如上圖可知,AMS經過IApplicationThread接口管理應用進程,ApplicationThread類實現了IApplicationThread接口,實現了管理應用的操做,ApplicationThread對象運行在應用進程裏。ApplicationThreadProxy對象是ApplicationThread對象在AMS線程 (AMS線程運行在system_server進程)內的代理對象,AMS經過ApplicationThreadProxy對象調用ApplicationThread提供的功能,好比讓應用進程啓動某個Activity。ApplicationThread中的scheduleDestroyActivity的源碼以下:

public final void scheduleDestroyActivity(IBinder token, boolean finishing,
               int configChanges) {
           sendMessage(H.DESTROY_ACTIVITY, token, finishing ? 1 : 0,
                   configChanges);
}

而Binder服務端的最終調用的是ActivityThread的sendMessage函數。

private void sendMessage(int what, Object obj, int arg1, int arg2) {
    sendMessage(what, obj, arg1, arg2, false);
}

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
    if (DEBUG_MESSAGES) Slog.v(
        TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
        + ": " + arg1 + " / " + obj);
    Message msg = Message.obtain();
    msg.what = what;
    msg.obj = obj;
    msg.arg1 = arg1;
    msg.arg2 = arg2;
    if (async) {
        msg.setAsynchronous(true);
    }
    mH.sendMessage(msg);
}

而ActivityThread類中內部類H(繼承自Handler,mH就是H的對象)中則定義了處理消息的方法,該函數用來處理接收到的數據。

AMS啓動Activity

前面講到AMS使用startActivity啓動APP,爲了加深印象在來看一下startActivity函數(須要注意的是,6.0和8.0的代碼有細微的區別)。

public final int startActivity(IApplicationThread caller, String callingPackage,
          Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
          int startFlags, ProfilerInfo profilerInfo, Bundle options) {
      return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
          resultWho, requestCode, startFlags, profilerInfo, options,
          UserHandle.getCallingUserId());
  }


  public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
        // 若是是隔離的應用的話,不容許其打開其餘app的activity
        //  appid是99000-99999之間的屬於隔離app
        enforceNotIsolatedCaller("startActivity");
        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, false, userId, null, null);
    }

判斷髮起者是不是隔離的app,不容許隔離的app調用其餘app。而後調用ActivityStackSupervisor類中的startActivityMayWait方法。

final int startActivityMayWait(
            IApplicationThread caller,//AMS經過這個參數能夠和發起者進行交互
            int callingUid,//發起者uid
            String callingPackage,//發起者包名
            Intent intent, // 啓動activity的intent
            String resolvedType, // intent的類型,也就是MIME type
            IVoiceInteractionSession voiceSession,
            IVoiceInteractor voiceInteractor,
            IBinder resultTo,//用於接收startActivityForResult的結果,launcher啓動app這種情景下沒有用,爲null
            String resultWho,
            int requestCode,//這個是調用者來定義其意義,若值大於等於0,則AMS內部保存該值並經過onActivityResult返回調用者,這裏爲-1
             int startFlags,// 傳入的爲0
            ProfilerInfo profilerInfo,
            WaitResult outResult,
            Configuration config,
            Bundle options,
            boolean ignoreTargetSecurity,
            int userId,
            IActivityContainer iContainer,  // 傳入的爲null
            TaskRecord inTask)/ // 傳入爲null
{
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors()) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }
        // 當啓動一個app時 ,launcher會構造一個intent,前面已經介紹了,是一個顯示的intent
        // 因此這裏爲true,
        boolean componentSpecified = intent.getComponent() != null;

        // Don't modify the client's object!
        // 建立一個新的intent,方便改動
        intent = new Intent(intent);

        // 收集 要啓動的app的主activity的信息
        ActivityInfo aInfo =
                resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);

        // 傳入的該參數爲null
        ActivityContainer container = (ActivityContainer)iContainer;
        synchronized (mService) {
            if (container != null && container.mParentActivity != null &&
                    container.mParentActivity.state != RESUMED) {
                // Cannot start a child activity if the parent is not resumed.
                return ActivityManager.START_CANCELED;
            }
        ....................................
            final ActivityStack stack;
            if (container == null || container.mStack.isOnHomeDisplay()) {
                stack = mFocusedStack;
            } else {
                stack = container.mStack;
            }
            // 傳入的config爲null
            stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                    "Starting activity when config will change = " + stack.mConfigWillChange);

            final long origId = Binder.clearCallingIdentity();

            if (aInfo != null &&
                    (aInfo.applicationInfo.privateFlags
                            &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
              .......................
              }

            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage,
                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
                    componentSpecified, null, container, inTask);

            Binder.restoreCallingIdentity(origId);

            if (stack.mConfigWillChange) {
              .............
            }
            // 傳入的爲null
            if (outResult != null) {
              .......................
                 mService.wait(); //等待應用進程的activity啓動完成
             ...........
            }
            .............
            }

            return res;
        }
    }

startActivityAsUser()方法最主要的目地是進行權限檢查,檢查發起者是否被隔離,是的話,是不容許調用別的app的activity的。startActivityMayWait()方法主要是利用傳入的intent去向PMS蒐集要啓動的APP的信息,儲存到aInfo中.。名字中有wait字眼,預示着該方法可能致使線程等待,不過在咱們這個場景中不會出現這種狀況,由於wait出如今對結果的處理中,咱們這個場景中是不須要處理結果的。
這裏寫圖片描述

ActivityThread.main

Android APP的入口類在ActivityThread中,有一個Main函數,該函數的源碼以下:

public static void main(String[] args) {
      Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
      SamplingProfilerIntegration.start();
      CloseGuard.setEnabled(false);

      // 環境初始化,主要是app運行過程當中須要使用到的系統路徑
      // 好比外部存儲路徑等等
      Environment.initForCurrentUser();

      // Set the reporter for event logging in libcore
      EventLogger.setReporter(new EventLoggingReporter());
      //增長一個保存key的provider
      AndroidKeyStoreProvider.install();

      // 爲應用社會當前用戶的CA證書保存的位置
      final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
      TrustedCertificateStore.setDefaultUserDirectory(configDir);
      // 設置app進程的名字
      // 經過前面的分析可知,前面的過程當中已經設置過名字了,這裏又改成了「pre-initialized」,不知道爲啥,
      // 由於後面還要在調用該方法,從新設置進程名字爲app 包名或者app指定的名字。
      Process.setArgV0("<pre-initialized>");
      // 建立主線程looper
      Looper.prepareMainLooper();
      // 建立ActivityThread對象。
      ActivityThread thread = new ActivityThread();
      // 將建立的ActivityThread附加到AMS中,這樣
      // AMS就能夠控制這個app中組件的生命週期了
      thread.attach(false);

      if (sMainThreadHandler == null) {
          sMainThreadHandler = thread.getHandler();
      }

      if (false) {
          Looper.myLooper().setMessageLogging(new
                  LogPrinter(Log.DEBUG, "ActivityThread"));
      }

      // End of event ActivityThreadMain.
      Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
      //App主線程開始執行消息處理循環
      Looper.loop();

      throw new RuntimeException("Main thread loop unexpectedly exited");
  }
}

當ActivityThread對象建立以後,就開始調用其attach()方法,這是一個很重要的方法,參數爲false代表是普通app進程。

private void attach(boolean system)
{
        sCurrentActivityThread = this;
        mSystemThread = system;
        // app進程傳入fasle
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            // mAppThread是ApplicationThread對象;
            // 下面這個方法會把mAppThread放到RuntimeInit類中的靜態變量mApplicationObject中
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                // 執行AMS的attachApplication方法
                // 將mAppThread傳入AMS,這樣AMS就能夠經過它來控制app了
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }
            // Watch for getting close to heap limit.
            BinderInternal.addGcWatcher(new Runnable() {
              ............
            });
        } else {
          ..............
        }

        // add dropbox logging to libcore
        DropBox.setReporter(new DropBoxReporter());

        ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
          .......
        });
    }

其中,RuntimeInit.setApplicationObject方法源碼以下:

public static final void setApplicationObject(IBinder app) {
       mApplicationObject = app;
   }

AMS的attachApplication方法

attachApplication方法主要負責APP與AMS的綁定操做,該方法的源碼以下:

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

該方法最終調用了attachApplicationLocked()方法。

private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        ProcessRecord app;
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
              // 在建立startProcessLocked()方法中調用Process.start()方法建立進程後
              // 會以接收傳遞過來的進程號爲索引,將ProcessRecord加入到AMS的mPidsSelfLocked中
              // 這裏能夠以進程號從mPidsSelfLocked中拿到ProcessRecord
                app = mPidsSelfLocked.get(pid);
            }
        } else {
            app = null;
        }
if (app == null) {
          ........
            return false;
        }
if (app.thread != null) {
       handleAppDiedLocked(app, true, true);
   }

   // 註冊app進程死亡通知處理機制,也就是建立監聽app死亡的對象
   // App進程死亡後,會調用AppDeathRecipient.binderDied()方法
   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;
   }
   //調用ProcessStatsService開始記錄process的狀態
   //該方法中將thread賦值給app.thread
   app.makeActive(thread, mProcessStats);
   // 初始化App進程優先級等信息
   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;
   // 移除PROC_START_TIMEOUT_MSG消息
   // 前面在AMS.startProcessLocked方法中會在調用Process.start()方法以後,將這個消息放入消息隊列中
   // 若是沒有在規定的時間內將該消息移除消息隊列,那麼會致使進程啓動超時
   mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

   // mProcessesReady爲true
   boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
   // 拿到App的provider
   List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
   ........
   // If the app is being launched for restore or full backup, set it up specially
   boolean isRestrictedBackupMode = false;
   if (mBackupTarget != null && mBackupAppName.equals(processName)) {
       isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
               || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
               || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
   }
   // 判斷是否須要執行dex2oat命令
   // 在app安裝的時候,會執行一次dex2oat
   // 當生成的oat文件被破外或者刪除的時候,須要從新執行dex2oat
   ensurePackageDexOpt(app.instrumentationInfo != null
                    ? app.instrumentationInfo.packageName
                    : app.info.packageName);
    //  instrument app 技術先關
    // 好比Android studio  開發時,修改某些代碼時,不必從新安裝apk,便可查看以後的結果
    // 後續單獨在分析instrument技術
    if (app.instrumentationClass != null) {
          ensurePackageDexOpt(app.instrumentationClass.getPackageName());
    }
    ....
    // 調用ApplicationThread的bindApplication接口
    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());
           updateLruProcessLocked(app, false, null);
           app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
       } catch (Exception e) {
          ............
           return false;
       }
    ....
    boolean badApp = false;
    boolean didSomething = false;
// See if the top visible activity is waiting to run in this process...
// 爲true
    if (normalMode) {
        try {
            // 執行ActivityStackSupervisor.attachApplicationLocked
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }
    // Find any services that should be running in this process...
    if (!badApp) {
        try {
            // 處理要運行這個進程中的service
            didSomething |= mServices.attachApplicationLocked(app, processName);
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
            badApp = true;
        }
    }

    // Check if a next-broadcast receiver is in this process...
    if (!badApp && isPendingBroadcastProcessLocked(pid)) {
        try {
            // 處理廣播
            didSomething |= sendPendingBroadcastsLocked(app);
        } catch (Exception e) {
            // If the app died trying to launch the receiver we declare it 'bad'
            Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
            badApp = true;
        }
    }
    ........
    if (!didSomething) {
           updateOomAdjLocked();
       }

       return true;
}

attachApplicationLocked函數比較長,首先以傳入的app進程號爲索引從AMS的mPidsSelfLocked中取出app進程的ProcessRecord對象。而後調用ProcessRecord對象的makeActive方法調用ProcessStatsService開始記錄process的狀態,接着將PROC_START_TIMEOUT_MSG消息,從消息循環中移除,檢查是否從新執行dex2oat生成app的oat文件。
該方法主要作了一下四件事情:

  • 調用ActivityThread的bindApplication方法去啓動Application;
  • 是調用ActivityStackSupervisor的attachApplicationLocked()方法去啓動ActivityStack棧頂的Activity;
  • 是ActiveServices調用的attachApplicationLocked()方法啓動在當前App進程中的service;
  • 是檢查是否有廣播broadcast到這個application,若是有則廣播。

其執行的流程圖以下圖所示:
這裏寫圖片描述

ApplicationThread.bindApplication方法

接下來重點分析下bindApplication()方法,這個方法最終效果是調用了App的Application對象的onCreate方法。其源碼以下:

public final void bindApplication(
                String processName, //ProcessRecord中記錄的進程名字
                ApplicationInfo appInfo,
                List<ProviderInfo> providers, // app中的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) {
                // Setup the service cache in the ServiceManager
                ServiceManager.initServiceCache(services);
            }

            // 發送SET_CORE_SETTINGS消息
            // 獲取系統的設定並設置到ActivityThread中
            setCoreSettings(coreSettings);

            // 拿到PMS
            IPackageManager pm = getPackageManager();
            android.content.pm.PackageInfo pi = null;
            try {
                // 以包名從PMS中得到PackageInfo
                pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId());
            } catch (RemoteException e) {
            }
            if (pi != null) {
                // 該app是否設置了共享uid
                boolean sharedUserIdSet = (pi.sharedUserId != null);
                // app進程名字是否被設定爲與包名不一致
                // 默認狀況下,app進程名字就是其包名
                // 當顯示設置process name 的時候能夠執行進程的名字
                boolean processNameNotDefault =
                (pi.applicationInfo != null &&
                 !appInfo.packageName.equals(pi.applicationInfo.processName));

                // 若是設置了共享uid或者進程名字設置爲了其餘名字,
                // 這就致使該app可能運行在一個已經運行的進程中
                boolean sharable = (sharedUserIdSet || processNameNotDefault);

                // 若是app是單獨的進程,那麼要想VM註冊相關信息
                // 是就上就在/data/dalvik-cache/profiles/建立一個以包名爲名字的空文件,另外兩個參數沒用到
                if (!sharable) {
                    VMRuntime.registerAppInfo(appInfo.packageName, appInfo.dataDir,
                                            appInfo.processName);
                }
            }
            // 建立兵初始化AppBindData對象
            // 在這裏設置了進程名字,app的provider,ApplicationInfo
            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;
            // 是否容許adb backup
            data.restrictedBackupMode = isRestrictedBackupMode;
            // 進程是否常駐內存,殺掉後,會被重啓
            data.persistent = persistent;
            data.config = config;
            data.compatInfo = compatInfo;
            data.initProfilerInfo = profilerInfo;
            // 發送BIND_APPLICATION消息
            sendMessage(H.BIND_APPLICATION, data);
        }

bindApplication()方法要經過PMS檢查啓動的app是否設置了共享uid,以及檢查當前app進程的名字是否設定的與包名不一致,符合二者中的任一種狀況下,則說明該app進程可能運行在另外一個已經存在的進程中。
bindApplication()方法主要是建立和初始化了AppBindData對象,併發送兩個消息:一個是SET_CORE_SETTINGS;另外一個是BIND_APPLICATION。SET_CORE_SETTINGS主要是獲取系統的設定並設置到ActivityThread中。BIND_APPLICATION用於啓動App並安裝全部的provider,並回調App的oncreate方法BIND_APPLICATION消息。
ActivityThread中處理BIND_APPLICATION消息的方法是handleBindApplication(),其源碼以下:

private void handleBindApplication(AppBindData data) {
    mBoundApplication = data;
   .......

    // 設置進程的名字,由於前面ActivityThread.main將其設置爲了"<pre-initialized>"
    Process.setArgV0(data.processName);
    // 設置app在ddms中顯示的進程名字
    android.ddm.DdmHandleAppName.setAppName(data.processName,
                                            UserHandle.myUserId());
    // 普通app進程,通常狀況下爲false
    // 除非xml設置persistent爲true   
    // 帶有persistent標記的進程在低內存設備中部支持使用硬件加速                                 
    if (data.persistent) {
        if (!ActivityManager.isHighEndGfx()) {
            HardwareRenderer.disable(false);
        }
    }

    if (mProfiler.profileFd != null) {
        mProfiler.startProfiling();
    }

    // 根據app編譯時指定的sdk版本與當前系統sdk版本設置AsyncTask
    if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
        AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    Message.updateCheckRecycle(data.appInfo.targetSdkVersion);

    // 恢復時區和位置信息
    TimeZone.setDefault(null);
    Locale.setDefault(data.config.locale);
    // 資源管理初始化設置
    mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
    mCurDefaultDisplayDpi = data.config.densityDpi;
    applyCompatConfiguration(mCurDefaultDisplayDpi);

    // 設置AppBindData中LoadedApk info屬性字段
    // 這裏會根據傳入app的ActivityInfo和CompatibilityInfo建立一個LoadedApk對象
    data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);

    // 若是應用沒有指定使用設備的density,那麼默認使用mdpi
    if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
            == 0) {
        mDensityCompatMode = true;
        Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
    }
    updateDefaultDensity();
    // 建立ContextImpl上下文,裏面也設計到了資源管理相關的內容 ,如從LoadedApk中提取資源
    // 後續還需對其進行初始化
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
    // 普通app啓動時,isIsolated爲false
    if (!Process.isIsolated()) {
        //在沙箱目錄中建立cache文件夾
        final File cacheDir = appContext.getCacheDir();

        if (cacheDir != null) {
            //將建立的cache文件夾與屬性"java.io.tmpdir"關聯
            System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
        } else {
            Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property due to missing cache directory");
        }

        // Use codeCacheDir to store generated/compiled graphics code
        // 在沙箱目錄建立code-cache文件夾
        final File codeCacheDir = appContext.getCodeCacheDir();
        if (codeCacheDir != null) {
            setupGraphicsSupport(data.info, codeCacheDir);
        } else {
            Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
        }
    }

    // 設置時間格式
    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;

    // 調試相關
    if ((data.appInfo.flags &
         (ApplicationInfo.FLAG_SYSTEM |
          ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
        StrictMode.conditionallyEnableDebugLogging();
    }

    if (data.appInfo.targetSdkVersion > 9) {
        StrictMode.enableDeathOnNetwork();
    }

    NetworkSecurityPolicy.getInstance().setCleartextTrafficPermitted(
            (data.appInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0);

    if (data.debugMode != IApplicationThread.DEBUG_OFF) {
      ............
    }

    // Enable OpenGL tracing if required
    if (data.enableOpenGlTrace) {
        GLUtils.setTracingLevel(1);
    }

    // Allow application-generated systrace messages if we're debuggable.
    boolean appTracingAllowed = (data.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0;
    Trace.setAppTracingAllowed(appTracingAllowed);

    /**
     * Initialize the default http proxy in this process for the reasons we set the time zone.
     */
    IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
    if (b != null) {
        IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
        try {
          // 設置網絡代理
            final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
            Proxy.setHttpProxySystemProperty(proxyInfo);
        } catch (RemoteException e) {}
    }
    // 爲null
    if (data.instrumentationName != null) {
      ..........
    } else {
      // 建立Instrumentation對象
        mInstrumentation = new Instrumentation();
    }
    if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
        dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
    } else {
        dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
    }
    final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
    try {
        // 建立app的Application對象
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;

        // don't bring up providers in restricted mode; they may depend on the
        // app's custom Application class
        if (!data.restrictedBackupMode) {
            List<ProviderInfo> providers = data.providers;
            if (providers != null) {
                installContentProviders(app, providers);
                // For process that contains content providers, we want to
                // ensure that the JIT is enabled "at some point".
                mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
            }
        }

        // Do this after providers, since instrumentation tests generally start their
        // test thread at this point, and we don't want that racing.
        try {
          // 執行instrumentation的onCreate()方法
            mInstrumentation.onCreate(data.instrumentationArgs);
        }
        catch (Exception e) {
          ................
        }
        // 執行Application的onCreate生命週期方法
        try {
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            ...............
        }
    } finally {
        StrictMode.setThreadPolicy(savedPolicy);
    }
}

handleBindApplication函數主要完成了以下的一些操做:

  1. 肯定了進程的最終名字,以及其在ddms中顯示的進程名字;
  2. 恢復進程的時區和位置信息;
  3. 調用getPackageInfoNoCheck()建立LoadApk對象;
  4. 建立ContextImpl對象,是AppContext;
  5. 設置網絡代理;
  6. 建立Instrumentation對象。

LoadedApk

LoadedApk類用來記錄描述一個被加載運行的APK,的代碼、資源等信息。

public final class LoadedApk {

    private static final String TAG = "LoadedApk";

    private final ActivityThread mActivityThread; // App的ActivityThread對象
    private ApplicationInfo mApplicationInfo;   // 描述App信息的ApplicationInfo,若是App中重載了Application類,那麼其類名會被記錄在ApplicationInfo中
    final String mPackageName;// app的包名
    private final String mAppDir;// app在/data/app/<包名>路徑
    private final String mResDir;// 資源路徑
    private final String[] mSplitAppDirs;
    private final String[] mSplitResDirs;
    private final String[] mOverlayDirs;
    private final String[] mSharedLibraries;// 共享java庫
    private final String mDataDir;//數據沙箱目錄
    private final String mLibDir;// native so庫位置
    private final File mDataDirFile;
    private final ClassLoader mBaseClassLoader;//getPackageInfoNoCheck()建立的LoadedApk對象中該字段初始化爲null
    private final boolean mSecurityViolation;
    private final boolean mIncludeCode;// 這個apk是否包含dex
    private final boolean mRegisterPackage;
    private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
    Resources mResources;
    private ClassLoader mClassLoader;//
    private Application mApplication;// 這個app的Application對象,若是App繼承了Application,那麼爲其子類對象

    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
        = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
        = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
    private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
        = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
    private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
        = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();

    int mClientCount = 0;

    Application getApplication() {
        return mApplication;
    }

經過分析可知,在handleBindApplication()方法中經過調用getPackageInfoNoCheck()方法建立LoadedApk對象。getPackageInfoNoCheck()的源碼以下:

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

getPackageInfoNoCheck()又調用了getPackageInfo()。

private LoadedApk getPackageInfo(
            ApplicationInfo aInfo, // app的Application信息
            CompatibilityInfo compatInfo, // 兼容性
            ClassLoader baseLoader,// 傳入null
            boolean securityViolation,// 傳入false
            boolean includeCode,// 傳入true
            boolean registerPackage // 傳入false
            ) {
// 要啓動app的擁有者與當前系統用戶不一致
final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
synchronized (mResourcesManager) {
    WeakReference<LoadedApk> ref;
    if (differentUser) {
        ref = null;
    } else if (includeCode) {
        // 若是包含了dex,那麼從ActivityThread.mPackages中先查找是否已經有了apk對應的LoadedApk
        ref = mPackages.get(aInfo.packageName);
    } else {
      // 若是沒有包含了dex,那麼從ActivityThread.mResourcePackages中先查找是否已經有了apk對應的LoadedApk
        ref = mResourcePackages.get(aInfo.packageName);
    }
    // 若是前面已經從mPackages或者mResourcePackages中找到了apk對應的LoadedApk,那麼就能夠直接返回了
    // 沒有找到的話,就要建立LoadedApk對象了
    if (packageInfo == null || (packageInfo.mResources != null
         && !packageInfo.mResources.getAssets().isUpToDate())) {

      // 建立LoadedApk對象
     packageInfo =
         new LoadedApk(this, aInfo, compatInfo, baseLoader,
                 securityViolation, includeCode &&
                 (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);

     if (mSystemThread && "android".equals(aInfo.packageName)) {
         packageInfo.installSystemApplicationInfo(aInfo,
                 getSystemContext().mPackageInfo.getClassLoader());
     }

     // 建立LoadedApk對象以後,將其加入對應的緩存列表中
     if (differentUser) {
         // Caching not supported across users
     } else if (includeCode) {
         mPackages.put(aInfo.packageName,
                 new WeakReference<LoadedApk>(packageInfo));
     } else {
         mResourcePackages.put(aInfo.packageName,
                 new WeakReference<LoadedApk>(packageInfo));
     }
  }
  return packageInfo;
}
}

由以上代碼可知,當要獲取一個LoadedApk對象時,先從ActivityThread的兩個緩存列表:mPackages和mResourcePackages中尋找,沒找到的話纔會新建LoadedApk對象,而後將其加入對應的緩存列表中。當找到apk對應的LoadedApk對象後,以此爲參數建立Application的Context對象。

final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
     if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
     return new ContextImpl(null, mainThread,
             packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
 }

private ContextImpl(
        ContextImpl container, // 傳入null
        ActivityThread mainThread,// app的ActivityThread對象
        LoadedApk packageInfo, // apk對應的LoadedApk對象
        IBinder activityToken, // 傳入爲null
        UserHandle user, boolean restricted,
        Display display, Configuration overrideConfiguration, int createDisplayWithId) {
    mOuterContext = this;

    mMainThread = mainThread;
    mActivityToken = activityToken;
    mRestricted = restricted;

    if (user == null) {
        user = Process.myUserHandle();
    }
    mUser = user;
    // context中會記錄apk對應的LoadedApk對象
    mPackageInfo = packageInfo;
    // 資源管理相關,後續單獨開篇介紹
    mResourcesManager = ResourcesManager.getInstance();
    ..............

    Resources resources = packageInfo.getResources(mainThread);
    if (resources != null) {
        if (displayId != Display.DEFAULT_DISPLAY
                || overrideConfiguration != null
                || (compatInfo != null && compatInfo.applicationScale
                        != resources.getCompatibilityInfo().applicationScale)) {
            resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
                    packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
                    packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
                    overrideConfiguration, compatInfo);
        }
    }
    mResources = resources;

    if (container != null) {
        mBasePackageName = container.mBasePackageName;
        mOpPackageName = container.mOpPackageName;
    } else {
        // 記錄app包名
        mBasePackageName = packageInfo.mPackageName;
        ApplicationInfo ainfo = packageInfo.getApplicationInfo();
        if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) {
            mOpPackageName = ActivityThread.currentPackageName();
        } else {
            mOpPackageName = mBasePackageName;
        }
    }
    // 內容提供者相關
    mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}

bindApplication()方法關鍵時序圖以下:
這裏寫圖片描述

在這個方法中建立了Classloader,以及Application對象。而後執行Application對象的attach方法,這個方法中又會調用attachBaseContext()方法。也就是說Application對象首先被執行的方法不是onCreate()方法,而是attach()方法。

attachApplicationLocked

由ActivityThread.main的總體執行時序圖中可知,啓動activity的最終是attachApplicationLocked()方法。

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    final String processName = app.processName;
    boolean didSomething = false;
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);
            // 從 如何啓動app中篇之Task的管理 可知,此時mFocusedStack指向即將要運行的activity所在的ActivityStack
            // 下面這個方法就是爲了從衆多ActivityStack找到這個ActivityStack
            if (!isFrontStack(stack)) {
                continue;
            }
            // 找到了所需的ActivityStack
            // 而後找到其棧頂的Activity,實際就是mTaskHistory數組末端的Task的頂端Activity
            ActivityRecord hr = stack.topRunningActivityLocked(null);
            if (hr != null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                        && processName.equals(hr.processName)) {
                    try {
                        if (realStartActivityLocked(hr, app, true, true)) {
                            didSomething = true;
                        }
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Exception in new application when starting activity "
                              + hr.intent.getComponent().flattenToShortString(), e);
                        throw e;
                    }
                }
            }
        }
    }
    if (!didSomething) {
        ensureActivitiesVisibleLocked(null, 0);
    }
    return didSomething;
}

ActivityStackSupervisor的流程調用關係能夠用下面的流程圖表示。

這裏寫圖片描述

相關文章
相關標籤/搜索