Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 7.0 ActivityManagerService(1) AMS的啟動過程

Android 7.0 ActivityManagerService(1) AMS的啟動過程

編輯:關於Android編程

一、概況
ActivityManagerService(AMS)是Android中最核心的服務,主要負責系統中四大組件的啟動、切換、調度及應用程序的管理和調度等工作。

AMS通信結構如下圖所示:

從圖中可以看出:
1、AMS繼承自ActivityManagerNative(AMN),並實現了Watchdog.Monitor和BatteryStatsImpl.BatteryCallback接口。

2、AMN繼承Java的Binder類,同時實現了IActivityManager接口,即AMN將作為Binder通信的服務端為用戶提供支持。

3、在ActivityManagerNative類中定義了內部類ActivityManagerProxy,該類同樣實現了IActivityManager接口,將作為客戶端使用的服務端代理。

4、其它進程將使用ActivityManager來使用AMS的服務。ActivityManager通過AMN提供的getDefault接口得到ActivityManagerProxy,然後再以Binder通信的方式調用AMS的接口。

對AMS的基本情況有一個大概的了解後,我們一起來分析一下AMS的啟動過程。
由於AMS啟動涉及的內容比較多,我們將分段進行分析。

二、createSystemContext
在進入到AMS相關的流程前,我們需要先了解一下相關的准備工作。

我們已經知道了,zygote創建出的第一個java進程是SystemServer。
在SystemServer的run函數中,在啟動AMS之前,調用了createSystemContext函數。

其代碼如下所示:

.............
//SystemServer在啟動任何服務之前,就調用了createSystemContext
//創建出的Context保存在mSystemContext中
// Initialize the system context.
createSystemContext();

// Create the system service manager.
//SystemServiceManager負責啟動所有的系統服務,使用的Context就是mSystemContext
mSystemServiceManager = new SystemServiceManager(mSystemContext);
.............

我們跟進一下createSystemContext:

private void createSystemContext() {
    //調用ActivityThread的systemMain函數,其中會創建出系統對應的Context對象
    ActivityThread activityThread = ActivityThread.systemMain();

    //取出上面函數創建的Context對象,保存在mSystemContext中
    mSystemContext = activityThread.getSystemContext();

    //設置系統主題
    mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
}

以上函數中,最重要的就是ActivityThread.systemMain了,我們分析一下該函數。

1、ActivityThread.systemMain

public static ActivityThread systemMain() {
    // The system process on low-memory devices do not get to use hardware
    // accelerated drawing, since this can add too much overhead to the
    // process.
    if (!ActivityManager.isHighEndGfx()) {
        //雖然寫著ActivityManager,但和AMS沒有任何關系
        //就是利用系統屬性和配置信息進行判斷

        //關閉硬件渲染功能
        ThreadedRenderer.disable(true);
    } else {
        ThreadedRenderer.enableForegroundTrimming();
    }

    //創建ActivityThread
    ActivityThread thread = new ActivityThread();
    //調用attach函數,參數為true
    thread.attach(true);
    return thread;
}

從上面的代碼可以看出,ActivityThread的systemMain函數中,除了進行是否開啟硬件渲染的判斷外,主要作用是:
創建出ActivityThread對象,然後調用該對象的attach函數。

ActivityThread的構造函數比較簡單:

ActivityThread() {
    mResourcesManager = ResourcesManager.getInstance();
}

比較關鍵的是它的成員變量:

..........
//定義了AMS與應用通信的接口
final ApplicationThread mAppThread = new ApplicationThread();

//擁有自己的looper,說明ActivityThread確實可以代表事件處理線程
final Looper mLooper = Looper.myLooper();

//H繼承Handler,ActivityThread中大量事件處理依賴此Handler
final H mH = new H();

//用於保存該進程的ActivityRecord
final ArrayMap mActivities = new ArrayMap<>()
..........
//用於保存進程中的Service
final ArrayMap mServices = new ArrayMap<>();
...........
//用於保存進程中的Application
final ArrayList mAllApplications = new ArrayList();
...........

我們需要知道的是,ActivityThread是Android Framework中一個非常重要的類,它代表一個應用進程的主線程,其職責就是調度及執行在該線程中運行的四大組件。
在Android中,應用進程指那些運行APK的進程,它們由zygote fork出來,其中運行著獨立的dalvik虛擬機。
與應用進程相對的就是系統進程,例如zygote和SystemServer。

注意到此處的ActivityThread創建於SystemServer進程中。
由於SystemServer中也運行著一些系統APK,例如framework-res.apk、SettingsProvider.apk等,因此也可以認為SystemServer是一個特殊的應用進程。

對於上面提到的ActivityThread的成員變量,其用途基本上可以從名稱中得知,這裡僅說明一下ApplicationThread。

AMS負責管理和調度進程,因此AMS需要通過Binder機制和應用進程通信。
為此,Android提供了一個IApplicationThread接口,該接口定義了AMS和應用進程之間的交互函數。

如上圖所示,ActivityThread作為應用進程的主線程代表,在其中持有ApplicationThread。ApplicationThread繼承ApplicationThreadNative。
當AMS與應用進程通信時,ApplicationThread將作為Binder通信的服務端。

AMS與應用進程通信時,通過ApplicationThreadNative獲取應用進程對應的ApplicationThreadProxy對象。
通過ApplicationThreadProxy對象,將調用信息通過Binder傳遞到ActivityThread中的ApplicationThread。
這個調用過程,今後還會遇到,碰到的時候再詳細分析。

2、ActivityThread.attach
我們看看ActivityThread的attach函數:

//此時,我們傳入的參數為true,表示該ActivityThread是系統進程的ActivityThread
private void attach(boolean system) {
    //創建出的ActivityThread保存在類的靜態變量sCurrentActivityThread
    //AMS中的大量操作將會依賴於這個ActivityThread
    sCurrentActivityThread = this;
    mSystemThread = system;

    if (!system) {
        //應用進程的處理流程
        ..........
    } else { 
        //系統進程的處理流程,該情況只在SystemServer中處理

        // Don't set application object here -- if the system crashes,
        // we can't display an alert, we just want to die die die.
        //設置DDMS(Dalvik Debug Monitor Service)中看到的SystemServer進程的名稱為“system_process”
        android.ddm.DdmHandleAppName.setAppName("system_process",
                UserHandle.myUserId());

        try {
            //創建ActivityThread中的重要成員:Instrumentation、Application和Context
            mInstrumentation = new Instrumentation();
            ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
            mInitialApplication = context.mPackageInfo.makeApplication(true, null);
            mInitialApplication.onCreate();
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to instantiate Application():" + e.toString(), e);
        }
    }

    //以下系統進程和非系統進程均會執行
    ................
    //注冊Configuration變化的回調通知
    ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            //當系統配置發生變化時(例如系統語言發生變化),回調該接口
            ...............
        }
        .............
    });
}

從上面的代碼可以看出,對於系統進程而言,ActivityThread的attach函數最重要的工作就是創建了Instrumentation、Application和Context。

2.1 Instrumentation
Instrumentation是Android中的一個工具類,當該類被啟用時,它將優先於應用中其它的類被初始化。
此時,系統先創建它,再通過它創建其它組件。

此外,系統和應用組件之間的交互也將通過Instrumentation來傳遞。
因此,Instrumentation就能監控系統和組件的交互情況了。

實際使用時,可以創建該類的派生類進行相應的操作。
這個類在介紹啟動Activity的過程時還會碰到,此處不作展開。

2.2 Context
Context是Android中的一個抽象類,用於維護應用運行環境的全局信息。
通過Context可以訪問應用的資源和類,甚至進行系統級的操作,例如啟動Activity、發送廣播等。

ActivityThread的attach函數中,通過下面的代碼創建出系統應用對應的Context:

.......
//ContextImpl是Context的實現類
ContextImpl context = ContextImpl.createAppContext(
        this, getSystemContext().mPackageInfo);
.......

2.2.1 getSystemContext
我們先看看ActivityThread中getSystemContext的內容:

public ContextImpl getSystemContext() {
    synchronized (this) {
        if (mSystemContext == null) {
            //調用ContextImpl的靜態函數createSystemContext
            mSystemContext = ContextImpl.createSystemContext(this);
        }
        return mSystemContext;
    }
}

進入ContextImpl的createSystemContext函數:

static ContextImpl createSystemContext(ActivityThread mainThread) {
    //創建LoadedApk類,代表一個加載到系統中的APK
    //注意此時的LoadedApk只是一個空殼
    //PKMS還沒有啟動,估無法得到有效的ApplicationInfo
    LoadedApk packageInfo = new LoadedApk(mainThread);

    //調用ContextImpl的構造函數
    ContextImpl context = new ContextImpl(null, mainThread,
            packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);

    //初始化資源信息
    context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
            context.mResourcesManager.getDisplayMetrics());
    return context;
}

可以看出createSystemContext的內容就是創建一個LoadedApk,然後初始化一個ContextImpl對象。
似乎沒有什麼特別的,那麼為什麼函數名被叫做create “System” Context?

為了回答這個問題,就要看看LoadedApk的構造函數了:

LoadedApk(ActivityThread activityThread) {
    mActivityThread = activityThread;
    mApplicationInfo = new ApplicationInfo();

    //packageName為"android"
    mApplicationInfo.packageName = "android";
    mPackageName = "android";
    //下面許多參數為null
    ................
}

注意到createSystemContext函數中,創建的LoadApk對應packageName為”android”,也就是framwork-res.apk。
由於該APK僅供SystemServer進程使用,因此創建的Context被定義為System Context。
現在該LoadedApk還沒有得到framwork-res.apk實際的信息。

當PKMS啟動,完成對應的解析後,AMS將重新設置這個LoadedApk。

2.2.2 ContextImpl.createAppContext

static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    return new ContextImpl(null, mainThread,
            packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
}

相對而言,createAppContext的內容就比較簡單了,就是利用ActivityThread和LoadedApk構造出ContextImpl。
ContextImpl的構造函數主要是完成一些變量的初始化,建立起ContextImpl與ActivityThread、LoadedApk、ContentResolver之間的關系。
代碼簡單但是冗長,此處不做展開。

2.3 Application
Android中Application類用於保存應用的全局狀態。

我們經常使用的Activity和Service均必須和具體的Application綁定在一起。
通過上圖的繼承關系,每個具體的Activity和Service均被加入到Android運行環境中。

在ActivityThread中,針對系統進程,通過下面的代碼創建了初始的Application:

..............
//調用LoadedApk的makeApplication函數
mInitialApplication = context.mPackageInfo.makeApplication(true, null);

//啟動Application
mInitialApplication.onCreate();
.............. 

我們看一下LoadedApk.makeApplication:

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {
        return mApplication;
    }
    .............
    Application app = null;

    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        //系統進程中,對應下面的appClass
        appClass = "android.app.Application";
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            ............
        }

        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        //實際上最後通過反射創建出Application
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
        ..........
    }

    //一個進程支持多個Application,mAllApplications用於保存該進程中的Application對象
    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    ..............
}

從上面的代碼不難看出,這部分主要是創建framework-res.apk對應的Application,然後調用它的onCreate函數,完成啟動。

總結
至此,createSystemContext函數介紹完畢。

當SystemServer調用createSystemContext完畢後:
1、得到了一個ActivityThread對象,它代表當前進程 (此時為系統進程) 的主線程;
2、得到了一個Context對象,對於SystemServer而言,它包含的Application運行環境與framework-res.apk有關。

在繼續分析AMS之前,我們先停下來思考一下,為什麼在啟動所有的服務前,SystemServer先要調用createSystemContext?

個人覺得《深入理解Android》對這個問題,解釋的比較好,大致意思如下:
Android努力構築了一個自己的運行環境。
在這個環境中,進程的概念被模糊化了。組件的運行及它們之間的交互均在該環境中實現。

createSystemContext函數就是為SystemServer進程搭建一個和應用進程一樣的Android運行環境。

Android運行環境是構建在進程之上的,應用程序一般只和Android運行環境交互。
基於同樣的道理,SystemServer進程希望它內部運行的應用,
也通過Android運行環境交互,因此才調用了createSystemContext函數。

創建Android運行環境時,
由於SystemServer的特殊性,調用了ActivityThread.systemMain函數;
對於普通的應用程序,將在自己的主線程中調用ActivityThread.main函數。

上圖表示了進程的Android運行環境涉及的主要類之間的關系。
其中的核心類是ContextImpl,通過它可以得到ContentResolver、系統資源、應用信息等。

三、AMS初始化
創建完Android運行環境後,SystemServer調用startBootstrapServices,其中就創建並啟動了AMS:

private void startBootstrapServices() {
    Installer installer = mSystemServiceManager.startService(Installer.class);

    // Activity manager runs the show.
    //啟動AMS,然後獲取AMS保存到變量中
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();

    //以下均是將變量存儲到AMS中
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);
    ..........
}

注意到上面的代碼並沒有直接啟動AMS,而是啟動AMS的內部類Lifecycle。
這是迫不得已的做法,由於AMS並沒有繼承SystemService,因此不能通過SystemServiceManager的startService直接啟動它。
可以這樣理解:內部類Lifecycle對於AMS而言,就像一個適配器一樣,讓AMS能夠像SystemService一樣被SystemServiceManager通過反射的方式啟動。

public static final class Lifecycle extends SystemService {
    private final ActivityManagerService mService;

    public Lifecycle(Context context) {
        //Lifecycle由SystemServiceManager啟動,傳入的context就是SystemServer創建出的SystemContext
        super(context);

        //1、調用AMS的構造函數
        mService = new ActivityManagerService(context);
     }

    @Override
    public void onStart() {
        //2、調用AMS的start函數
        mService.start();
    }

    public ActivityManagerService getService() {
        return mService;
    }
}

接下來我們分別看看AMS的構造函數和start函數。

1、AMS的構造函數
先來看看AMS的構造函數:

public ActivityManagerService(Context systemContext) {
    //AMS的運行上下文與SystemServer一致
    mContext = systemContext;
    ............
    //取出的是ActivityThread的靜態變量sCurrentActivityThread
    //這意味著mSystemThread與SystemServer中的ActivityThread一致
    mSystemThread = ActivityThread.currentActivityThread();
    ............
    mHandlerThread = new ServiceThread(TAG,
            android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
    mHandlerThread.start();
    //處理AMS中消息的主力
    mHandler = new MainHandler(mHandlerThread.getLooper());

    //UiHandler對應於Android中的UiThread
    mUiHandler = new UiHandler();

    if (sKillHandler == null) {
        sKillThread = new ServiceThread(TAG + ":kill",
                android.os.Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
        sKillThread.start();
        //用於接收消息,殺死進程
        sKillHandler = new KillHandler(sKillThread.getLooper());
    }

    //創建兩個BroadcastQueue,前台的超時時間為10s,後台的超時時間為60s
    mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "foreground", BROADCAST_FG_TIMEOUT, false);
    mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "background", BROADCAST_BG_TIMEOUT, true);
    mBroadcastQueues[0] = mFgBroadcastQueue;
    mBroadcastQueues[1] = mBgBroadcastQueue;

    //創建變量,用於存儲信息
    mServices = new ActiveServices(this);
    mProviderMap = new ProviderMap(this);
    mAppErrors = new AppErrors(mContext, this);

    //這一部分,分析BatteryStatsService時提過,進行BSS的初始化
    File dataDir = Environment.getDataDirectory();
    File systemDir = new File(dataDir, "system");
    systemDir.mkdirs();
    mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
    mBatteryStatsService.getActiveStatistics().readLocked();
    mBatteryStatsService.scheduleWriteToDisk();
    mOnBattery = DEBUG_POWER ? true
            : mBatteryStatsService.getActiveStatistics().getIsOnBattery();
    mBatteryStatsService.getActiveStatistics().setCallback(this);

    //創建ProcessStatsService,感覺用於記錄進程運行時的統計信息,例如內存使用情況,寫入/proc/stat文件
    mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));

    //啟動Android的權限檢查服務,並注冊對應的回調接口
    mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);
    mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_IN_BACKGROUND, null,
            new IAppOpsCallback.Stub() {
                @Override public void opChanged(int op, int uid, String packageName) {
                    if (op == AppOpsManager.OP_RUN_IN_BACKGROUND && packageName != null) {
                        if (mAppOpsService.checkOperation(op, uid, packageName)
                                != AppOpsManager.MODE_ALLOWED) {
                            runInBackgroundDisabled(uid);
                        }
                    }
                }
            });

    //用於定義ContentProvider訪問指定Uri對應數據的權限,aosp中似乎沒有這文件
    mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));

    //創建多用戶管理器
    mUserController = new UserController(this);

    //獲取OpenGL版本
    GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
            ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
    ............
    //資源配置信息置為默認值
    mConfiguration.setToDefaults();
    mConfiguration.setLocales(LocaleList.getDefault());
    mConfigurationSeq = mConfiguration.seq = 1;

    //感覺用於記錄進程的CPU使用情況
    mProcessCpuTracker.init();

    //解析/data/system/packages-compat.xml文件,該文件用於存儲那些需要考慮屏幕尺寸的APK的一些信息
    //當APK所運行的設備不滿足要求時,AMS會根據xml設置的參數以采用屏幕兼容的方式運行該APK
    mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);

    //用於根據規則過濾一些Intent
    mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);

    //以下的類,似乎用於管理和監控AMS維護的Activity Task信息
    //ActivityStackSupervisor是AMS中用來管理Activity啟動和調度的核心類
    mStackSupervisor = new ActivityStackSupervisor(this);
    mActivityStarter = new ActivityStarter(this, mStackSupervisor);
    mRecentTasks = new RecentTasks(this, mStackSupervisor);

    //創建線程用於統計進程的CPU使用情況
    mProcessCpuThread = new Thread("CpuTracker") {
        @Override
        public void run() {
            while (true) {
                try {
                    try {
                        //計算更新信息的等待間隔
                        //同時利用wait等待計算出的間隔時間
                        ......
                    } catch(InterruptedException e) {
                    }
                    //更新CPU運行統計信息
                    updateCpuStatsNow();
                } catch (Exception e) {
                    ..........
                }
            }
        }
    };

    //加入Watchdog的監控
    Watchdog.getInstance().addMonitor(this);
    Watchdog.getInstance().addThread(mHandler);
}

從代碼來看,AMS的構造函數還是相對比較簡單的,主要工作就是初始化一些變量。
大多數變量的用途,從命名上基本可以推測出來,實際的使用情況必須結合具體的場景才能進一步了解。

2、AMS的start函數

private void start() {
    //完成統計前的復位工作
    Process.removeAllProcessGroups();

    //開始監控進程的CPU使用情況
    mProcessCpuThread.start();

    //注冊服務
    mBatteryStatsService.publish(mContext);
    mAppOpsService.publish(mContext);
    Slog.d("AppOps", "AppOpsService published");
    LocalServices.addService(ActivityManagerInternal.class, new LocalService());
}

AMS的start函數比較簡單,主要是:
1、啟動CPU監控線程。該線程將會開始統計不同進程使用CPU的情況。
2、發布一些服務,如BatteryStatsService、AppOpsService(權限管理相關)和本地實現的繼承ActivityManagerInternal的服務。

至此AMS初始化相關的內容基本結束,從這些代碼可以看出AMS涉及的類比較多,我們目前無法一一詳述每個類的具體用途。
有機會遇到具體的場景時,再深入分析,此處有個大致印象即可。

四、將SystemServer納入AMS的管理體系
1、setSystemProcess

AMS完成啟動後,在SystemServer的startBootstrapServices函數中,
下一個與AMS相關的重要調用就是AMS.setSystemProcess了:

private void startBootstrapServices() {
    ...........
    // Set up the Application instance for the system process and get started.
    mActivityManagerService.setSystemProcess();
    ...........
}

我們跟進一下setSystemProcess函數:

public void setSystemProcess() {
    try {
        //以下是向ServiceManager注冊幾個服務

        //AMS自己
        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);

        //注冊進程統計信息的服務
        ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);

        //用於打印內存信息用的
        ServiceManager.addService("meminfo", new MemBinder(this));

        //用於輸出進程使用硬件渲染方面的信息
        ServiceManager.addService("gfxinfo", new GraphicsBinder(this));

        //用於輸出數據庫相關的信息
        ServiceManager.addService("dbinfo", new DbBinder(this));

        //MONITOR_CPU_USAGE默認為true
        if (MONITOR_CPU_USAGE) {
            //用於輸出進程的CPU使用情況
            ServiceManager.addService("cpuinfo", new CpuBinder(this));
        }

        //注冊權限管理服務
        ServiceManager.addService("permission", new PermissionController(this));

        //注冊獲取進程信息的服務
        ServiceManager.addService("processinfo", new ProcessInfoService(this));

        //1、向PKMS查詢package名為“android”的應用的ApplicationInfo
        ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                "android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);

        //2、調用installSystemApplicationInfo
        mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());

        //3、以下與AMS的進程管理有關
        synchronized (this) {
            ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
            app.persistent = true;
            app.pid = MY_PID;
            app.maxAdj = ProcessList.SYSTEM_ADJ;
            app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.put(app.pid, app);
            }
            updateLruProcessLocked(app, false, null);
            updateOomAdjLocked();
        }
    } catch (PackageManager.NameNotFoundException e) {
        throw new RuntimeException(
                "Unable to find android system package", e);
    }
}

從上面的代碼可以看出,AMS的setSystemProcess主要有四個主要的功能:
1、注冊一些服務;
2、獲取package名為“android”的應用的ApplicationInfo;
3、調用ActivityThread的installSystemApplicationInfo;
4、AMS進程管理相關的操作。

這四個主要的功能中,第一個比較簡單,就是用Binder通信完成注冊。
我們主要看看後三個功能對應的流程。

1.1 獲取ApplicationInfo
如前所述,這部分相關的代碼為:

..........
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
        "android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);
..........

1.1.1 獲取PKMS服務代理
我們先看看mContext.getPackageManager()的操作過程。

我們已經知道mContext的實現類是ContextImpl,其中對應的代碼如下:

@Override
public PackageManager getPackageManager() {
    if (mPackageManager != null) {
        return mPackageManager;
    }

    //依賴於ActivityThread的getPackageManager函數
    IPackageManager pm = ActivityThread.getPackageManager();
    if (pm != null) {
        // Doesn't matter if we make more than one instance.
        //利用PKMS的代理對象,構建ApplicationPackageManager
        //該類繼承PackageManager
        return (mPackageManager = new ApplicationPackageManager(this, pm));
    }

    return null;
}

跟進一下ActivityThread中的getPackageManager:

public static IPackageManager getPackageManager() {
    if (sPackageManager != null) {
        //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
        return sPackageManager;
    }
    //依賴於Binder通信,獲取到PKMS對應的BpBinder
    IBinder b = ServiceManager.getService("package");
    .....................
    //得到PKMS對應的Binder服務代理
    sPackageManager = IPackageManager.Stub.asInterface(b);
    ....................
    return sPackageManager;
}

從上面的代碼我們可以看到,AMS獲取PKMS用到了Binder通信。

實際上,PKMS由SystemServer創建,與AMS運行在同一個進程。
AMS完全可以不經過Context、ActivityThread、Binder來獲取PKMS。

根據一些資料,推斷出原生代碼這麼做的原因是:
SystemServer進程中的服務,也使用Android運行環境來交互,
保留了組件之間交互接口的統一,為未來的系統保留了可擴展性。

1.1.2 通過PKMS獲取ApplicationInfo
得到PKMS的代理對象後,AMS調用PKMS的getApplicationInfo接口,獲取package名為”android”的ApplicationInfo。

在AMS的setSystemProcess被調用前,PKMS已經啟動了。
之前分析PKMS的博客中,我們已經提到,在PKMS的構造函數中,
它將解析手機中所有的AndroidManifest.xml,然後形成各種數據結構以維護應用的信息。

getApplicationInfo就是通過package名,從對應的數據結構中,取出對應的應用信息。
這部分內容主要就是查詢數據結構的內容,不作深入分析。

1.2 installSystemApplicationInfo
得到framework-res.apk對應的ApplicationInfo後,需要將這部分ApplicationInfo保存到SystemServer對應的ActivityThread中。

這部分對應的代碼為:

..............
mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
..............

AMS中的mSystemThread就是SystemServer中創建出的ActivityThread。
因此我們跟進一下ActivityThread的installSystemApplicationInfo函數:

public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
    synchronized (this) {
        //調用SystemServer中創建出的ContextImpl的installSystemApplicationInfo函數
        getSystemContext().installSystemApplicationInfo(info, classLoader);

        // give ourselves a default profiler
        //創建一個Profiler對象,用於性能統計
        mProfiler = new Profiler();
    }
}

繼續跟進ContextImpl的installSystemApplicationInfo函數:

void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
    //前面已經提到過mPackageInfo的類型為LoadedApk
    mPackageInfo.installSystemApplicationInfo(info, classLoader);
}

隨著流程進入到LoadedApk:

/**
* Sets application info about the system package.
*/
void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
    //這個接口僅供系統進程調用,故這裡斷言一下
    assert info.packageName.equals("android");

    mApplicationInfo = info;
    mClassLoader = classLoader;
}

至此,我們知道了installSystemApplicationInfo的真相就是:
將“android”對應的ApplicationInfo(即framework-res.apk對應的ApplicationInfo),
加入到SystemServer之前調用createSystemContext時,創建出的LoadedApk中。
畢竟SystemServer創建System Context時,PKMS並沒有完成對手機中文件的解析,初始的LoadedApk中並沒有持有有效的ApplicationInfo。

在此基礎上,AMS下一步的工作就呼之欲出了。

由於framework-res.apk運行在SystemServer進程中,而AMS是專門用於進程管理和調度的,
因此SystemServer進程也應該在AMS中有對應的管理結構。

於是,AMS的下一步工作就是將SystemServer的運行環境和一個進程管理結構對應起來,並進行統一的管理。

1.3 AMS進程管理注意到上面的ContentProvider注冊到AMS後,進行了notifyAll的操作。
舉例來說:進程A需要查詢一個數據庫,需要通過進程B中的某個ContentProvider來實施。
如果B還未啟動,那麼AMS就需要先啟動B。在這段時間內,A需要等待B啟動並注冊對應的ContentProvider。
B一旦完成ContentProvider的注冊,就需要告知A退出等待以繼續後續的查詢工作。
setSystemProcess函數中,進程管理相關的代碼為:

.............
synchronized (this) {
    //創建進程管理對應的結構ProcessRecord
    ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);

    //由於此時創建的是SystemServer進程對應ProcessRecord
    //因此設定了一些特殊值
    app.persistent = true;
    app.pid = MY_PID;
    app.maxAdj = ProcessList.SYSTEM_ADJ;

    //將SystemServer對應的ApplicationThread保存到ProcessRecord中
    app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);

    synchronized (mPidsSelfLocked) {
        //按pid將ProcessRecord保存到mPidsSelfLocked中
        mPidsSelfLocked.put(app.pid, app);
    }

    //updateLruProcessLocked來調整進程在mLruProcess列表的位置
    //在這個列表中,最近活動過得進程總是位於前列,同時擁有Activity的進程位置總是前於只有Service的進程
    updateLruProcessLocked(app, false, null);

    //更新進程對應的oom_adj值(oom_adj將決定進程是否被kill掉)
    updateOomAdjLocked();
}
...............

這裡我們僅分析一下創建進程管理結構的函數newProcessRecordLocked。
updateLruProcessLocked和updateOomAdjLocked函數比較復雜,等對AMS有更多的了解後,再做分析。

final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
        boolean isolated, int isolatedUid) {
    //進程的名稱
    String proc = customProcess != null ? customProcess : info.processName;

    //將用於創建該進程的電源統計項
    BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();

    final int userId = UserHandle.getUserId(info.uid);
    //isolated此時為false
    if (isolated) {
        ..........
    }
    //創建出對應的存儲結構
    final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);

    //判斷進程是否常駐
    if (!mBooted && !mBooting
            && userId == UserHandle.USER_SYSTEM
            && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
        r.persistent = true;
    }

    //按進程名將ProcessRecord存入到AMS的變量mProcessNames中
    //該變量的類型為ProcessMap 
    //結合前面的代碼,我們知道AMS有兩種方式可以取到ProcessRecord
    //一是根據進程名,二是根據進程名稱
    addProcessNameLocked(r);
    return r;
}

跟進一下ProcessRecord的構造函數:

ProcessRecord(BatteryStatsImpl _batteryStats, ApplicationInfo _info,
        String _processName, int _uid) {
    mBatteryStats = _batteryStats; //用於電量統計
    info = _info;  //保存ApplicationInfo
    ...........
    processName = _processName;  //保存進程名

    //一個進程能運行多個Package,pkgList用於保存package名
    pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.versionCode));

    //以下變量和進程調度優先級有關
    maxAdj = ProcessList.UNKNOWN_ADJ;
    curRawAdj = setRawAdj = ProcessList.INVALID_ADJ;
    curAdj = setAdj = verifiedAdj = ProcessList.INVALID_ADJ;

    //決定進程是否常駐內存(即使被殺掉,系統也會重啟它)
    persistent = false;

    removed = false;
    lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
}

總結
至此,我們對AMS的setSystemProcess函數分析告一段落。
從上面的代碼可以看出,在這個函數中除了發布一些服務外,主要是:
將framework-res.apk的信息加入到SystemServer對應的LoadedApk中,同時構建SystemServer進程對應的ProcessRecord,
以將SystemServer進程納入到AMS的管理中。

2、AMS的installSystemProviders
接下來AMS啟動相關的操作,定義於SystemServer的startOtherServices函數中。

private void startOtherServices() {
    ...........
    mActivityManagerService.installSystemProviders();
    ...........
}

我們跟進一下AMS的installSystemProviders函數:

public final void installSystemProviders() {
    List providers;
    synchronized (this) {
        //AMS根據進程名取出SystemServer對應的ProcessRecord
        ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);

        //1、得到該ProcessRecord對應的ProviderInfo
        providers = generateApplicationProvidersLocked(app);

        //這裡僅處理系統級的Provider
        if (providers != null) {
            for (int i=providers.size()-1; i>=0; i--) {
                ProviderInfo pi = (ProviderInfo)providers.get(i);
                    if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
                        Slog.w(TAG, "Not installing system proc provider " + pi.name
                                + ": not system .apk");
                        providers.remove(i);
                    }
                }
            }
        }
    }

    if (providers != null) {
        //2、安裝Provider
        mSystemThread.installSystemProviders(providers);
    }

    //創建ContentObserver監控Settings數據庫中Secure、System和Global表的變化
    mCoreSettingsObserver = new CoreSettingsObserver(this);

    //創建ContentObserver監控Settings數據庫中字體大小的變化
    mFontScaleSettingObserver = new FontScaleSettingObserver();
}

從上面的代碼可以看出,installSystemProviders主要是加載運行在SystemServer進程中的ContentProvider,即SettingsProvider.apk (定義於frameworks/base/packages/SettingsProvider)。

上面有兩個比較重要的函數:
1、generateApplicationProvidersLocked返回一個進程對應的ProviderInfo List。
2、ActivityThread可以看做是進程的Android運行環境,因此它的installSystemProviders表示為對應進程安裝ContentProvider。

當SettingsProvider被加載到SystemServer進程中運行後,AMS就注冊了兩個ContentObserver監控SettingsProvider中的字段變化。
AMS監控的字段影響范圍比較廣,例如字體發生變化時,很多應用的顯示界面都需要做出調整。
這也許就是讓AMS來負責監控這些字段的原因。

接下來,我們分別看看上述比較重要的兩個函數。

2.1 generateApplicationProvidersLocked

private final List generateApplicationProvidersLocked(ProcessRecord app) {
    List providers = null;
    try {
        //利用PKMS根據進程名及權限,從數據結構中得到進程對應ProviderInfo
        providers = AppGlobals.getPackageManager()
                .queryContentProviders(app.processName, app.uid,
                        STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
                            | MATCH_DEBUG_TRIAGED_MISSING)
                .getList();
    } catch (RemoteException ex) {
    }
    .............
    int userId = app.userId;
    if (providers != null) {
        int N = providers.size();
        //寫這行代碼的人,一定是個極客!!!!
        //通常而言,我們逐漸向容器加入數據時,容器只有在數據超出當前存儲空間時
        //才會進行內存的重新分配(一般是乘2)和數據的拷貝
        //因此若待加入數據總量很大,在逐步向容器加入數據的過程中,容器將會有多次重新分配和拷貝的過程
        //或許整體的開銷並不是很驚人,但事先將內存一次分配到位,體現了對極致的追求 (情不自禁的寫了這段話。。。)
        app.pubProviders.ensureCapacity(N + app.pubProviders.size());

        for (int i=0; i

整體來講generateApplicationProvidersLocked函數的思想很簡單,最主要的功能是: 從PKMS中得到應用對應的ContentProvider,然後利用應用信息和對應的ContentProvider組成ContentProviderRecord, 並按包名存儲到AMS的mProviderMap中。

AMS保存ProviderInfo的原因是:它需要管理ContentProvider。 此外,我們看到ProcessRecord也保存了ProviderInfo,這是因為ContentProvider最終要落實到一個進程中。

這也是為了方便AMS的管理,畢竟一個進程退出時,AMS需要將其中運行的ContentProvider信息從系統中移除。

generateApplicationProvidersLocked中唯一稍微繞了點彎的地方是,針對多用戶的情況,判斷了ContentProvider是否為單例的。 就像我注釋裡寫的,個人覺得在多用戶的場景下,“同一個”進程變成了多個,分別運行在每個用戶對應的空間中。 假設ContentProvider在對應的xml中定義了,運行在指定進程A中。 那麼當多個用戶都加載進程A時(此時進程名或許相似,但不是一個進程), A進程中定義的ContentProvider將被加載多次,分別運行在各個用戶的進程A中。 但是當一個ContentProvider是單例的,那麼該ContentProvider僅會被加載在系統用戶(類似於administrator)啟動的進程中。

雖然目前多用戶的場景比較少,ContentProvider到底運行在哪個進程中,可能也不是那麼重要。 但本著學習的態度,我們還是看看isSingleton的實現:

boolean isSingleton(String componentProcessName, ApplicationInfo aInfo,
        String className, int flags) {
    boolean result = false;
    // For apps that don't have pre-defined UIDs, check for permission
    //非系統用戶,就是多了個權限檢查
    //是否單例還是取決於ServiceInfo.FLAG_SINGLE_USER
    if (UserHandle.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
         if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
            if (ActivityManager.checkUidPermission(
                    INTERACT_ACROSS_USERS,
                    aInfo.uid) != PackageManager.PERMISSION_GRANTED) {
                //無權限,則拋出異常
                .............
            }
         }
         // Permission passed
         result = true;
    } else if ("system".equals(componentProcessName)) {
        result = true;
    } else if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
        // Phone app and persistent apps are allowed to export singleuser providers.
        result = UserHandle.isSameApp(aInfo.uid, Process.PHONE_UID)
                 || (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
    }
    .............
    return result;
}

從上面的代碼,我們知道了:
對於非系統用戶而言,當Provider的flag包含ServiceInfo.FLAG_SINGLE_USER時,它是單例的;
對於系統用戶而言,當Provider運行在系統進程中,或者 該Provider運行在(Phone進程或常駐進程)且(包含ServiceInfo.FLAG_SINGLE_USER)時,它是單例的。

至此,我們知道了generateApplicationProvidersLocked函數,主要就是用於得到和保存對應進程的ContentProvider信息。

2.2 installSystemProviders
得到運行在進程中的ContentProvider的信息後,當然要進行安裝了。
對於運行在SystemServer中的ContentProvider,AMS將調用ActivityThread的installSystemProviders進行處理。

public final void installSystemProviders(List providers) {
    if (providers != null) {
        //對於SystemServer進程而言,mInitialApplication是framework-res.apk對應的Application
        installContentProviders(mInitialApplication, providers);
    }
}

private void installContentProviders(
        Context context, List providers) {
    final ArrayList results =
            new ArrayList();

    for (ProviderInfo cpi : providers) {
        ..............
        //1、初始化並保存ContentProvider
        IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
        if (cph != null) {
            cph.noReleaseNeeded = true;
            results.add(cph);
        }
    }

    try {
        //2、向AMS注冊ContentProvider
        ActivityManagerNative.getDefault().publishContentProviders(
                getApplicationThread(), results);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
}

installContentProviders是安裝ContentProvider時的通用程序,主要包括兩方面的工作:
1、調用installProvider得到IActivityManager.ContentProviderHolder對象,其間完成了對應ContentProvider的初始化等工作。
2、向AMS發布這個IActivityManager.ContentProviderHolder。

2.2.1 installProvider

private IActivityManager.ContentProviderHolder installProvider(Context context,
        IActivityManager.ContentProviderHolder holder, ProviderInfo info,
        boolean noisy, boolean noReleaseNeeded, boolean stable) {
    ContentProvider localProvider = null;
    IContentProvider provider;
    if (holder == null || holder.provider == null) {
        //此時holder==null, 進入這個分支
        ............
        Context c = null;
        ApplicationInfo ai = info.applicationInfo;

        //下面判斷的作用是:為待安裝的ContentProvider找到對應的Application
        //在AndroidManifest.xml中,ContentProvider是Application的子標簽,
        //因此ContentProvider與Application有一種對應關系
        //在本次的流程中,傳入的Context是mInitialApplication,代表的是framework-res.apk
        //而Provider代表的是SettingsProvider, SettingsProvider.apk所對應的Application還未創建

        if (context.getPackageName().equals(ai.packageName)) {
            c = context;
        } else if (mInitialApplication != null &&
            mInitialApplication.getPackageName().equals(ai.packageName)) {
            c = mInitialApplication;
        } else {
            try {
                //以下將創建一個Context,指向SettingsProvider.apk
                //ai.packageName為com.android.provider.settings

                //利用package對應的LoadedApk信息,創建ContextImpl
                //當前主線程如果加載過這個LoadedApk,將從存儲變量中取出LoadedApk
                //否則將通過PKMS得到對應的ApplicationInfo,並以ApplicationInfo構建出LoadedApk,然後保存在存儲變量中
                c = context.createPackageContext(ai.packageName,
                        Context.CONTEXT_INCLUDE_CODE);
            } catch (PackageManager.NameNotFoundException e) {
                // Ignore
            }
        }
        ..................
        try {
            //除了ContextProvider與Application的對應關系外,必須先找到ContextProvider對應的Context的另一個原因是:
            //只有正確的Context才能加載對應APK的Java字節碼,從而通過反射的方式創建出ContextProvider實例

            //得到對應的ClassLoader
            final java.lang.ClassLoader cl = c.getClassLoader();

            //反射創建實例
            localProvider = (ContentProvider)cl.
                    loadClass(info.name).newInstance();

            //得到ContentProvider的mTransport對象
            //表現類型為接口IContentProvider,實際為ContentProviderNative,即ContentProvider的Binder通信服務端
            provider = localProvider.getIContentProvider();
            ..................
            //初始化ContentProvider,內部會調用ContentProvder的onCreate函數
            localProvider.attachInfo(c, info);
        } catch(java.lang.Exception e) {
            ............
        }
    } else {
        provider = holder.provider;
        if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
                + info.name);
    }

    IActivityManager.ContentProviderHolder retHolder;

    synchronized (mProviderMap) {
        ...............
        //調用ContentProviderNative的asBinder
        IBinder jBinder = provider.asBinder();
        if (localProvider != null) {
            ComponentName cname = new ComponentName(info.packageName, info.name);
            ProviderClientRecord pr = mLocalProvidersByName.get(cname);
            if (pr != null) {
                ............
            } else {
                //創建ContentProviderHolder持有ContentProvider
                holder = new IActivityManager.ContentProviderHolder(info);
                holder.provider = provider;
                holder.noReleaseNeeded = true;
                //構造ProviderClientRecord,並按authority將ProviderClientRecord存入mProviderMap
                pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                mLocalProviders.put(jBinder, pr);
                mLocalProvidersByName.put(cname, pr);
            }
            retHolder = pr.mHolder;
        } else {
            ...............
        }
    }

    return retHolder;
}

installProvider的代碼較長,但實際思想很簡單,就是環環相扣的三步:
1、創建出ContentProvider對應的ContextImpl(代表對應的運行環境);
2、利用ContextImpl得到對應的ClassLoader,完成ContentProvider的初始化和啟動;
3、得到與ContentProvider通信的BpBinder,然後按名稱和BpBinder,將ContentProvider保存到對應的存儲結構中。

ActivityThread與ContentProvider的關系大概如上圖所示。
ContentProvider本身只是一個容器,其內部持有的Transport類才能提供對跨進程調用的支持。
Transport類繼承自ContentProviderNative類,作為ContentProvider的Binder通信服務端。
ContentProviderNative中定義了ContentProvderProxy類,將作為Binder通信的服務端代理。

如上代碼所示,ActivityThread用mLocalProviders保存運行在本地的ContentProvider時,
使用的鍵值就是ContentProvider的Binder通信服務端。

2.2.2 publishContentProviders
ContentProvider初始化完成後,我們需要向AMS注冊它。
如前所述,在ActivityThread的installContentProviders函數中,將通過下面這段代碼進行注冊:

..........
ActivityManagerNative.getDefault().publishContentProviders(
        getApplicationThread(), results);
.........

這段代碼是注冊ContentProvider的通用代碼,因此即使我們現在的流程運行在AMS中,此處仍然將通過Binder通信進行調用。
ActivityManagerNative.getDefault()將得到ActivityManagerProxy對象,因此上面代碼實際上調用的是ActivityManagerProxy.publishContentProviders:

//ActivityThread注冊ContentProvider時,傳入了自己的ApplicationThread,
//當AMS與ActivityThread通信時,ApplicationThread作為Binder通信的服務端
public void publishContentProviders(IApplicationThread caller,
        List providers) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeTypedList(providers);
    //消息打包完成後,發往服務端AMS
    mRemote.transact(PUBLISH_CONTENT_PROVIDERS_TRANSACTION, data, reply, 0);
    reply.readException();
    data.recycle();
    reply.recycle();
}

在AMS父類AMN的onTransact函數中:

public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
    switch (code) {
        .......
        case PUBLISH_CONTENT_PROVIDERS_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            //得到ApplicationThread的BpBinder
            IBinder b = data.readStrongBinder();

            //得到ActivityThread中ApplicationThread的服務端代理
            IApplicationThread app = ApplicationThreadNative.asInterface(b);

            //解析出消息
            ArrayList providers =
                    data.createTypedArrayList(ContentProviderHolder.CREATOR);

            //AMN調用子類的函數
            publishContentProviders(app, providers);
            reply.writeNoException();
            return true;
        }
        .......
    }
    .........
}

跟著流程,現在我們看看AMS中的publishContentProviders函數:

public final void publishContentProviders(IApplicationThread caller,
        List providers) {
    if (providers == null) {
        return;
    }
    ...........
    synchronized (this) {
        //找到調用者對應的ProcessRecord對象
        final ProcessRecord r = getRecordForAppLocked(caller);
        ...........
        final int N = providers.size();
        for (int i = 0; i < N; i++) {
            ContentProviderHolder src = providers.get(i);
            ............
            //ProcessRecord的pubProviders中保存了ContentProviderRecord信息
            //這是根據PKMS解析出的Package信息生成的
            //此處主要判斷將要發布的ContentProvider是否由該Pacakge聲明
            ContentProviderRecord dst = r.pubProviders.get(src.info.name);
            ............
            if (dst != null) {
                ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
                //按名稱保存到mProviderMap
                mProviderMap.putProviderByClass(comp, dst);
                ...............
                String names[] = dst.info.authority.split(";");
                for (int j = 0; j < names.length; j++) {
                    //按authority保存到mProviderMap
                    mProviderMap.putProviderByName(names[j], dst);
                }
            }

            //mLaunchingProviders保存處於啟動狀態的Provider
            int launchingCount = mLaunchingProviders.size();
            int j;
            boolean wasInLaunchingProviders = false;
            for (j = 0; j < launchingCount; j++) {
                if (mLaunchingProviders.get(j) == dst) {
                    //這個ContentProvider完成啟動,從隊列中移除
                    mLaunchingProviders.remove(j);
                    wasInLaunchingProviders = true;
                    j--;
                    launchingCount--;
                }
            }
            if (wasInLaunchingProviders) {
                //取消啟動超時的消息
                mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
            }
            synchronized (dst) {
                dst.provider = src.provider;
                dst.proc = r;
                //通知等待那些等待ContentProvider所在進程啟動的客戶端進程
                dst.notifyAll();
            }
            //每發布一個ContentProvder,均調整對應進程的oom_adj
            updateOomAdjLocked(r);
            //判斷,並在需要時更新ContentProvider相關的統計信息
            maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                    src.info.authority);
        }
    }
    ..........
}

publishContentProviders函數結束後,一個ContentProvider就算正式在系統中注冊了。
在AMS的啟動過程中,此處注冊的是SettingsProvider。
此後,Settings數據庫相關的操作均由它來管理。

注意到上面的ContentProvider注冊到AMS後,進行了notifyAll的操作。
舉例來說:進程A需要查詢一個數據庫,需要通過進程B中的某個ContentProvider來實施。
如果B還未啟動,那麼AMS就需要先啟動B。在這段時間內,A需要等待B啟動並注冊對應的ContentProvider。
B一旦完成ContentProvider的注冊,就需要告知A退出等待以繼續後續的查詢工作。

五、AMS的systemReady
接下來,我們看看AMS啟動的最後一部分:systemReady。
該函數在SystemServer中startOtherServices的最後被調用:

private void startOtherServices() {
    ............
    // 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.
    mActivityManagerService.systemReady(new Runnable() {
        ..............
    });
}

我們分段看看AMS中systemReady的處理流程。
此處的分段並沒有實際的意義,只是代碼確實太長了,並且連續性不夠,因此分開描述。

1 階段一

public void systemReady(final Runnable goingCallback) {
    synchronized(this) {
        ..........
        //這一部分主要是調用一些關鍵服務SystemReady相關的函數,
        //進行一些等待AMS初始完,才能進行的工作

        // Make sure we have the current profile info, since it is needed for security checks.
        mUserController.onSystemReady();

        mRecentTasks.onSystemReadyLocked();
        mAppOpsService.systemReady();
        mSystemReady = true;
    }

    ArrayList procsToKill = null;
    synchronized(mPidsSelfLocked) {
        //mPidsSelfLocked中保存當前正在運行的所有進程的信息
        for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
            ProcessRecord proc = mPidsSelfLocked.valueAt(i);

            //在AMS啟動完成前,如果沒有FLAG_PERSISTENT標志的進程已經啟動了,
            //就將這個進程加入到procsToKill中
            if (!isAllowedWhileBooting(proc.info)){
                if (procsToKill == null) {
                    procsToKill = new ArrayList();
                }
                procsToKill.add(proc);
            }
        }
    }

    synchronized(this) {
        //利用removeProcessLocked關閉procsToKill中的進程
        if (procsToKill != null) {
            for (int i=procsToKill.size()-1; i>=0; i--) {
                ProcessRecord proc = procsToKill.get(i);
                Slog.i(TAG, "Removing system update proc: " + proc);
                removeProcessLocked(proc, true, false, "system update done");
            }
        }

        // Now that we have cleaned up any update processes, we
        // are ready to start launching real processes and know that
        // we won't trample on them any more.

        //至此系統准備完畢
        mProcessesReady = true;
    }
    ............
    //根據數據庫和資源文件,獲取一些配置參數
    retrieveSettings();

    final int currentUserId;
    synchronized (this) {
        //得到當前的用戶ID
        currentUserId = mUserController.getCurrentUserIdLocked();

        //讀取urigrants.xml,為其中定義的ContentProvider配置對指定Uri數據的訪問/修改權限
        //原生代碼中,似乎沒有urigrants.xml文件
        //實際使用的grant-uri-permission是分布式定義的
        readGrantedUriPermissionsLocked();
    }
    ..........

這一部分的工作主要是調用一些關鍵服務的初始化函數,
然後殺死那些沒有FLAG_PERSISTENT卻在AMS啟動完成前已經存在的進程,
同時獲取一些配置參數。
需要注意的是,由於只有Java進程才會向AMS注冊,而一般的Native進程不會向AMS注冊,因此此處殺死的進程是Java進程。

2 階段二

//1、調用參數傳入的runnable對象,SystemServer中有具體的定義
if (goingCallback != null) goingCallback.run();
..............
//調用所有系統服務的onStartUser接口
mSystemServiceManager.startUser(currentUserId);
.............
synchronized (this) {
    // Only start up encryption-aware persistent apps; once user is
    // unlocked we'll come back around and start unaware apps
    2、啟動persistent為1的application所在的進程
    startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);

    // Start up initial activity.
    mBooting = true;

    // Enable home activity for system user, so that the system can always boot
    //當isSplitSystemUser返回true時,意味者system user和primary user是分離的
    //這裡應該是讓system user也有啟動home activity的權限吧
    if (UserManager.isSplitSystemUser()) {
        ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
        try {
            AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
                    UserHandle.USER_SYSTEM);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
    }

    //3、啟動Home
    startHomeActivityLocked(currentUserId, "systemReady");

    try {
        //發送消息,觸發處理Uid錯誤的Application
        if (AppGlobals.getPackageManager().hasSystemUidErrors()) {
            ..........
            mUiHandler.obtainMessage(SHOW_UID_ERROR_UI_MSG).sendToTarget();
        }
    } catch (RemoteException e) {
    }
    //發送一些廣播信息
    ............
    //這裡暫時先不深入,等進一步了解Activity的啟動過程後,再做了解
    mStackSupervisor.resumeFocusedStackTopActivityLocked();
    ............
}
.............

從部分代碼來看,主要的工作就是通知一些服務可以進行systemReady相關的工作,並進行啟動服務或應用進程的工作。

2.1 調用回調接口
回調接口的具體內容定義與SystemServer.java中,其中會調用大量服務的onBootPhase函數、一些對象的systemReady函數或systemRunning函數。
此處,我們僅截取一些比較特別的內容:

public void run() {
    ............
    try {
        //啟動NativeCrashListener監聽"/data/system/ndebugsocket"中的信息
        //實際上是監聽debuggerd傳入的信息
        mActivityManagerService.startObservingNativeCrashes();
    } catch (Throwable e) {
        reportWtf("observing native crashes", e);
    }
    ............
    try {
        //啟動SystemUi
        startSystemUi(context);
    } catch (Throwable e) {
        reportWtf("starting System UI", e);
    }
    ............
    //這個以前分析過,啟動Watchdog
    Watchdog.getInstance().start();
    ....................
}

回調接口中的內容較多,不做一一分析。

2.2 啟動persistent標志的進程
我們看看startPersistentApps對應的內容:

private void startPersistentApps(int matchFlags) {
    .............

    synchronized (this) {
        try {
            //從PKMS中得到persistent為1的ApplicationInfo
            final List apps = AppGlobals.getPackageManager()
                    .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
            for (ApplicationInfo app : apps) {
                //由於framework-res.apk已經由系統啟動,所以此處不再啟動它
                if (!"android".equals(app.packageName)) {
                    //addAppLocked中將啟動application所在進程
                    addAppLocked(app, false, null /* ABI override */);
                }
            }
        } catch (RemoteException ex) {
        }
    }
}

跟進一下addAppLocked函數:

final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
        String abiOverride) {
    //以下是取出或構造出ApplicationInfo對應的ProcessRecord
    ProcessRecord app;
    if (!isolated) {
        app = getProcessRecordLocked(info.processName, info.uid, true);
    } else {
        app = null;
    }

    if (app == null) {
        app = newProcessRecordLocked(info, null, isolated, 0);
        updateLruProcessLocked(app, false, null);
        updateOomAdjLocked();
    }
    ...........
    // This package really, really can not be stopped.
    try {
        //通過PKMS將package對應數據結構的StoppedState置為fasle
        AppGlobals.getPackageManager().setPackageStoppedState(
                info.packageName, false, UserHandle.getUserId(app.uid));
    } catch (RemoteException e) {
    } catch (IllegalArgumentException e) {
        Slog.w(TAG, "Failed trying to unstop package "
                + info.packageName + ": " + e);
    }

    if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
        app.persistent = true;
        app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
    }

    if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
        mPersistentStartingProcesses.add(app);
        //啟動應用所在進程,將發送消息給zygote,後者fork出進程
        startProcessLocked(app, "added application", app.processName, abiOverride,
                null /* entryPoint */, null /* entryPointArgs */);
    }

    return app;
}

這裡最終將通過startProcessLocked函數,啟動實際的應用進程。
正如之前分析zygote進程時,提過的一樣,zygote中的server socket將接收消息,然後為應用fork出進程。

2.3 啟動Home Activity
看看啟動Home Activity對應的startHomeActivityLocked函數:

boolean startHomeActivityLocked(int userId, String reason) {
    ..............
    Intent intent = getHomeIntent();
    //根據intent中攜帶的ComponentName,利用PKMS得到ActivityInfo
    ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
        intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
        aInfo = new ActivityInfo(aInfo);
        aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);

        //此時home對應進程應該還沒啟動,app為null
        ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                aInfo.applicationInfo.uid, true);
        if (app == null || app.instrumentationClass == null) {
            intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
            //啟動home
            mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
        }
    } else {
        ..........
    }
    return true;
}

這裡暫時先不深究Home Activity啟動的具體過程。
從手頭的資料來看,當Home Activity啟動後,
ActivityStackSupervisor中的activityIdleInternalLocked函數將被調用(具體調用過程,還需要研究):

final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
        Configuration config) {
    ...........
    if (isFocusedStack(r.task.stack) || fromTimeout) {
        booting = checkFinishBootingLocked();
    }
    ............
}

在checkFinishBootingLocked函數中:

private boolean checkFinishBootingLocked() {
    //mService為AMS,mBooting變量在AMS回調SystemServer中定義的Runnable時,置為了true
    final boolean booting = mService.mBooting;
    boolean enableScreen = false;
    mService.mBooting = false;
    if (!mService.mBooted) {
        mService.mBooted = true;
        enableScreen = true;
    }
    if (booting || enableScreen) {、
        //調用AMS的接口,發送消息
        mService.postFinishBooting(booting, enableScreen);
    }
    return booting;
}

最終,AMS的finishBooting函數將被調用:

final void finishBooting() {
    .........
    //以下是注冊廣播接收器,用於處理需要重啟的package
    IntentFilter pkgFilter = new IntentFilter();
    pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
    pkgFilter.addDataScheme("package");
    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
            if (pkgs != null) {
                for (String pkg : pkgs) {
                    synchronized (ActivityManagerService.this) {
                        if (forceStopPackageLocked(pkg, -1, false, false, false, false, false,
                                0, "query restart")) {
                            setResultCode(Activity.RESULT_OK);
                            return;
                        }
                    }
                }
            }
       }
    }, pkgFilter);
    ...........
    // Let system services know.
    mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);

    //以下是啟動那些等待啟動的進程
    synchronized (this) {
        // Ensure that any processes we had put on hold are now started
        // up.
        final int NP = mProcessesOnHold.size();
            if (NP > 0) {
                ArrayList<processrecord> procs =
                        new ArrayList<processrecord>(mProcessesOnHold);
                for (int ip=0; ip<np; .................="" ..............="" if="" mfactorytest="" start="" looking="" for="" apps="" that="" are="" abusing="" wake="" locks.="" message="" nmsg="mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);" tell="" anyone="" interested="" we="" done="" ams="" pre="">

最終,當AMS啟動Home Activity結束,並發送ACTION_BOOT_COMPLETED廣播時,AMS的啟動過程告一段落。

總結 對於整個AMS啟動過程而言,博客中涉及的內容可能只是極小的一部分。 但即使我們盡可能的簡化,整個過程的內容還是非常多。

不過我們回頭看看整個過程,還是能比較清晰地將AMS的啟動過程分為四步,如上圖所示: 1、創建出SystemServer進程的Android運行環境。 在這一部分,SystemServer進程主要創建出對應的ActivityThread和ContextImpl,構成Android運行環境。 AMS的後續工作依賴於SystemServer在此創建出的運行環境。

2、完成AMS的初始化和啟動。 在這一部分,單純地調用AMS的構造函數和start函數,完成AMS的一些初始化工作。

3、將SystemServer進程納入到AMS的管理體系中。 AMS作為Java世界的進程管理和調度中心,要對所有Java進程一視同仁,因此SystemServer進程也必須被AMS管理。 在這個過程中,AMS加載了SystemServer中framework-res.apk的信息,並啟動和注冊了SettingsProvider.apk。

4、開始執行AMS啟動完畢後才能進行的工作。 系統中的一些服務和進程,必須等待AMS完成啟動後,才能展開後續工作。 在這一部分,AMS通過調用systemReady函數,通知系統中的其它服務和進程,可以進行對應工作了。 在這個過程中,值得我們關注的是:Home Activity被啟動了。當該Activity被加載完成後,最終會觸發ACTION_BOOT_COMPLETED廣播。

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