Android元件框架:Android元件管理者ActivityManager

蘇策發表於2017-12-19

關於作者

郭孝星,程式設計師,吉他手,主要從事Android平臺基礎架構方面的工作,歡迎交流技術方面的問題,可以去我的Github提issue或者發郵件至guoxiaoxingse@163.com與我交流。

第一次閱覽本系列文章,請參見導讀,更多文章請參見文章目錄

文章目錄

  • 一 元件管家ActivityManagerService
    • 1.1 ActivityManagerService啟動流程
    • 1.1 ActivityManagerService工作流程
  • 二 應用主執行緒ActivityThread
    • 2.1 ActivityThread啟動流程
    • 2.2 ActivityThread工作

ActivityManagerService是貫穿Android系統元件的核心服務,在ServiceServer執行run()方法的時候被建立,執行在獨立的執行緒中,負責Activity、Service、BroadcastReceiver的啟動、切換、排程以及應用程式的管理和排程工作。

Activity、Service、BroadcastReceiver的啟動、切換、排程都有著相似的流程,我們來看一下。

Activity的啟動流程圖(放大可檢視)如下所示:

Android元件框架:Android元件管理者ActivityManager

主要角色有:

  • Instrumentation: 監控應用與系統相關的互動行為。
  • AMS:元件管理排程中心,什麼都不幹,但是什麼都管。
  • ActivityStarter:處理Activity什麼時候啟動,怎麼樣啟動相關問題,也就是處理Intent與Flag相關問題,平時提到的啟動模式都可以在這裡找到實現。
  • ActivityStackSupervisior:這個類的作用你從它的名字就可以看出來,它用來管理Stack和Task。
  • ActivityStack:用來管理棧裡的Activity。
  • ActivityThread:最終幹活的人,是ActivityThread的內部類,Activity、Service、BroadcastReceiver的啟動、切換、排程等各種操作都在這個類裡完成。

Service的啟動流程圖(放大可檢視)如下所示:

Android元件框架:Android元件管理者ActivityManager

主要角色有:

  • AMS:元件管理排程中心,什麼都不幹,但是什麼都管。
  • ApplicationThread:最終幹活的人,是ActivityThread的內部類,Activity、Service、BroadcastReceiver的啟動、切換、排程等各種操作都在這個類裡完成。
  • ActiveServices:主要用來管理Service,內部維護了三份列表:將啟動Service列表、重啟Service列表以及以銷燬Service列表。

BroadcastReceiver的啟動流程圖(放大可檢視)如下所示:

Android元件框架:Android元件管理者ActivityManager

主要角色有:

  • AMS:元件管理排程中心,什麼都不幹,但是什麼都管。
  • BroadcastQueue:廣播佇列,根據廣播的優先順序來管理廣播。
  • ApplicationThread:最終幹活的人,是ActivityThread的內部類,Activity、Service、BroadcastReceiver的啟動、切換、排程等各種操作都在這個類裡完成。
  • ReceiverDispatcher:廣播排程中心,採用反射的方式獲取BroadcastReceiver的例項,然後呼叫它的onReceive()方法。

可以發現,除了一些輔助類外,最主要的元件管家AMS和應用主執行緒ActivityThread。本篇文章重點分析這兩個類的實現,至於其他類會在 Activity、Service與BroadcastReceiver啟動流程的文章中一一分析。

通過上面的分析,AMS的整個排程流程就非常明朗了。

ActivityManager相當於前臺接待,她將客戶的各種需求傳達給大總管ActivityMangerService,但是大總管自己不幹活,他招來了很多小弟,他最信賴的小弟ActivityThread 替他完成真正的啟動、切換、以及退出操作,至於其他的中間環節就交給ActivityStack、ActivityStarter等其他小弟來完成。

一 元件管家ActivityManagerService

1.1 ActivityManagerService啟動流程

我們知道所有的系統服務都是在SystemServer的run()方法裡啟動的,SystemServer 將系統服務分為了三類:

  • 引導服務
  • 核心服務
  • 其他服務

ActivityManagerService屬於引導服務,在startBootstrapServices()方法裡被建立,如下所示:

mActivityManagerService = mSystemServiceManager.startService(
        ActivityManagerService.Lifecycle.class).getService();
複製程式碼

SystemServiceManager的startService()方法利用反射來建立物件,Lifecycle是ActivityManagerService裡的靜態內部類,它繼承於SystemService,在它的構造方法裡 它會呼叫ActivityManagerService的構造方法建立ActivityManagerService物件。

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

    public Lifecycle(Context context) {
        super(context);
        mService = new ActivityManagerService(context);
    }

    @Override
    public void onStart() {
        mService.start();
    }

    public ActivityManagerService getService() {
        return mService;
    }
}
複製程式碼

ActivityManagerService的構造方法如下所示:

public ActivityManagerService(Context systemContext) {
    mContext = systemContext;
    mFactoryTest = FactoryTest.getMode();
    mSystemThread = ActivityThread.currentActivityThread();

    Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());

    //建立並啟動系統執行緒以及相關Handler
    mHandlerThread = new ServiceThread(TAG,
            android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
    mHandlerThread.start();
    mHandler = new MainHandler(mHandlerThread.getLooper());
    mUiHandler = new UiHandler();
    /* static; one-time init here */
    if (sKillHandler == null) {
        sKillThread = new ServiceThread(TAG + ":kill",
                android.os.Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
        sKillThread.start();
        sKillHandler = new KillHandler(sKillThread.getLooper());
    }

    //建立用來儲存各種元件Activity、Broadcast的資料結構
    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);

    //建立system等各種資料夾,用來記錄系統的一些事件
    ...
    
    //初始化一些記錄工具
    ...
}
複製程式碼

可以發現,ActivityManagerService的構造方法主要做了兩個事情:

  • 建立並啟動系統執行緒以及相關Handler。
  • 建立用來儲存各種元件Activity、Broadcast的資料結構。

這裡有個問題,這裡建立了兩個Hanlder(sKillHandler暫時忽略,它是用來kill程式的)分別是MainHandler與UiHandler,它們有什麼區別呢??

我們知道Handler是用來向所線上程傳送訊息的,也就是說決定Handler定位的是它構造方法裡的Looper,我們分別來看下。

MainHandler裡的Looper來源於執行緒ServiceThread,它的執行緒名是"ActivityManagerService",該Handler主要用來處理元件排程相關操作。

mHandlerThread = new ServiceThread(TAG,
        android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
mHandlerThread.start();
mHandler = new MainHandler(mHandlerThread.getLooper());
複製程式碼

UiHandler裡的Looper來源於執行緒UiThread(繼承於ServiceThread),它的執行緒名"android.ui",該Handler主要用來處理UI相關操作。


private UiThread() {
    super("android.ui", Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
    // Make sure UiThread is in the fg stune boost group
    Process.setThreadGroup(Process.myTid(), Process.THREAD_GROUP_TOP_APP);
}

public UiHandler() {
    super(com.android.server.UiThread.get().getLooper(), null, true);
}
複製程式碼

以上便是整個ActivityManagerService的啟動流程,還是比較簡單的。

1.2 ActivityManagerService工作流程

ActivityManagerService就是ActivityManager家族 的核心類了,四大元件的啟動、切換、排程都是在ActivityManagerService裡完成的。

ActivityManagerService類圖如下所示:

Android元件框架:Android元件管理者ActivityManager
  • ActivityManager:AMS給客戶端呼叫的介面。
  • ActivityManagerNative:該類是ActivityManagerService的父類,繼承與Binder,主要用來負責程式通訊,接收ActivityManager傳遞過來的資訊,這麼寫可以將通訊部分分離在ActivityManagerNative,使得 ActivityManagerService可以專注元件的排程,減小了類的體積。
  • ActivityManagerProxy:該類定義在ActivityManagerNative內部,正如它的名字那樣,它是ActivityManagerService的代理類,

關於ActivityManager

ActivityManager是提供給客戶端呼叫的介面,日常開發中我們可以利用 ActivityManager來獲取系統中正在執行的元件(Activity、Service)、程式(Process)、任務(Task)等資訊,ActivityManager定義了相應的方法來獲取和操作這些資訊。

ActivityManager定義了很多靜態內部類來描述這些資訊,具體說來:

  • ActivityManager.StackId: 描述元件棧ID資訊
  • ActivityManager.StackInfo: 描述元件棧資訊,可以利用StackInfo去系統中檢索某個棧。
  • ActivityManager.MemoryInfo: 系統可用記憶體資訊
  • ActivityManager.RecentTaskInfo: 最近的任務資訊
  • ActivityManager.RunningAppProcessInfo: 正在執行的程式資訊
  • ActivityManager.RunningServiceInfo: 正在執行的服務資訊
  • ActivityManager.RunningTaskInfo: 正在執行的任務資訊
  • ActivityManager.AppTask: 描述應用任務資訊

說道這裡,我們有必要區分一些概念,以免以後混淆。

  • 程式(Process):Android系統進行資源排程和分配的基本單位,需要注意的是同一個棧的Activity可以執行在不同的程式裡。
  • 任務(Task):Task是一組以棧的形式聚集在一起的Activity的集合,這個任務棧就是一個Task。

在日常開發中,我們一般是不需要直接操作ActivityManager這個類,只有在一些特殊的開發場景才用的到。

  • isLowRamDevice():判斷應用是否執行在一個低記憶體的Android裝置上。
  • clearApplicationUserData():重置app裡的使用者資料。
  • ActivityManager.AppTask/ActivityManager.RecentTaskInfo:我們如何需要操作Activity的棧資訊也可以通過ActivityManager來做。

關於ActivityManagerNative與ActivityManagerProxy

這兩個類其實涉及的是Android的Binder通訊原理,後面我們會有專門的文章來分析Binder相關實現。

二 應用主執行緒ActivityThread

ActivityThread管理著應用程式裡的主執行緒,負責Activity、Service、BroadcastReceiver的啟動、切換、 以及銷燬等操作。

2.1 ActivityThread啟動流程

先來聊聊ActivityThread,這個類也厲害了?,它就是我們app的入口,寫過Java程式的同學都知道,Java程式的入口類都會有一個main()方法,ActivityThread也是這樣,它的main()方法在新的應用 程式被建立後就會被呼叫,我們來看看這個main()方法實現了什麼東西。

public final class ActivityThread {
    
     public static void main(String[] args) {
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
         SamplingProfilerIntegration.start();
 
         // CloseGuard defaults to true and can be quite spammy.  We
         // disable it here, but selectively enable it later (via
         // StrictMode) on debug builds, but using DropBox, not logs.
         CloseGuard.setEnabled(false);
 
         Environment.initForCurrentUser();
 
         // Set the reporter for event logging in libcore
         EventLogger.setReporter(new EventLoggingReporter());
 
         // Make sure TrustedCertificateStore looks in the right place for CA certificates
         final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
         TrustedCertificateStore.setDefaultUserDirectory(configDir);
 
         Process.setArgV0("<pre-initialized>");
         //主執行緒的looper
         Looper.prepareMainLooper();
         //建立ActivityThread例項
         ActivityThread thread = new ActivityThread();
         //呼叫attach()方法將ApplicationThread物件關聯給AMS,以便AMS呼叫ApplicationThread裡的方法,這同樣也是一個IPC的過程。
         thread.attach(false);
 
         //主執行緒的Handler
         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);
         //開始訊息迴圈
         Looper.loop();
 
         throw new RuntimeException("Main thread loop unexpectedly exited");
     }   
}
複製程式碼

這裡面還有關鍵的attach()方法,我們來看一下。

public final class ActivityThread {
    
   private void attach(boolean system) {
        sCurrentActivityThread = this;
        //判斷是否為系統程式,上面傳過來的為false,表明它不是一個系統程式
        mSystemThread = system;
        //應用程式的處理流程
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                //將ApplicationThread物件關聯給AMS,以便AMS呼叫ApplicationThread裡的方法,這
                //同樣也是一個IPC的過程。
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            // Watch for getting close to heap limit.
            BinderInternal.addGcWatcher(new Runnable() {
                @Override public void run() {
                    if (!mSomeActivitiesChanged) {
                        return;
                    }
                    Runtime runtime = Runtime.getRuntime();
                    long dalvikMax = runtime.maxMemory();
                    long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                    if (dalvikUsed > ((3*dalvikMax)/4)) {
                        if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                                + " total=" + (runtime.totalMemory()/1024)
                                + " used=" + (dalvikUsed/1024));
                        mSomeActivitiesChanged = false;
                        try {
                            mgr.releaseSomeActivities(mAppThread);
                        } catch (RemoteException e) {
                            throw e.rethrowFromSystemServer();
                        }
                    }
                }
            });
        } 
        //系統程式的處理流程
        else {
            //初始化系統元件,例如:Instrumentation、ContextImpl、Application
            //系統程式的名稱為system_process
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                //建立Instrumentation物件
                mInstrumentation = new Instrumentation();
                //建立ContextImpl物件
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                //建立Application物件
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                //呼叫Application.onCreate()方法,這個方法我們非常熟悉了,我們經常在這裡做一些初始化庫的工作。
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }

        // add dropbox logging to libcore
        DropBox.setReporter(new DropBoxReporter());
        
        //註冊Configuration變化後的回撥通知,當系統配置發生變化時,例如:語言切換,觸發該回撥。
        ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
            //配置發生變化
            @Override
            public void onConfigurationChanged(Configuration newConfig) {
                synchronized (mResourcesManager) {
                    // We need to apply this change to the resources
                    // immediately, because upon returning the view
                    // hierarchy will be informed about it.
                    if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
                        updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                                mResourcesManager.getConfiguration().getLocales());

                        // This actually changed the resources!  Tell
                        // everyone about it.
                        if (mPendingConfiguration == null ||
                                mPendingConfiguration.isOtherSeqNewer(newConfig)) {
                            mPendingConfiguration = newConfig;

                            sendMessage(H.CONFIGURATION_CHANGED, newConfig);
                        }
                    }
                }
            }
            //低記憶體
            @Override
            public void onLowMemory() {
            }
            @Override
            public void onTrimMemory(int level) {
            }
        });
    }
}
複製程式碼

從上面這兩個方法我們可以看出ActivityThread主要做了兩件事情:

  • 建立並開啟主執行緒的訊息迴圈。
  • 將ApplicationThread物件(Binder物件)關聯給AMS,以便AMS呼叫ApplicationThread裡的方法,這同樣也是一個IPC的過程。

2.2 ActivityThread工作流程

ActivityThread工作流程圖如下所示:

Android元件框架:Android元件管理者ActivityManager

通過前面的分析,ActivityThread的整個工作流程就非常明朗了。ActivityThread內部有個Binder物件ApplicationThread,AMS可以呼叫ApplicationThread裡的方法,而 ApplicationThread裡的方法利用mH(Handler)傳送訊息給ActivityThread裡的訊息佇列,ActivityThread再去處理這些訊息,進而完成諸如Activity啟動等各種操作。

到這裡我們已經把ActivityManager家族的主要框架都梳理完了,本篇文章並沒有大篇幅的去分析原始碼,我們的重點是梳理整體框架,讓大家有整體上的認識,至於具體的細節,可以根據自己的需要有的 放矢的去研究。這也是我們提倡的閱讀Android原始碼的方法:不要揪著細節不放,要有整體意識。

理解了AMS的內容,後續就接著來分析Activity、Service、BroadcastReceiver的啟動、切換和銷燬等流程,分析的過程中也會結合著日常開發中經常遇到的一些問題,帶著這些問題,我們去看看源 碼裡怎麼寫的,為什麼會出現這些問題。應該如何去解決。

相關文章