美文网首页Andriod插件化
ActivityManagerService架构剖析开篇

ActivityManagerService架构剖析开篇

作者: 码上就说 | 来源:发表于2018-07-06 14:46 被阅读235次

    ActivityManagerService是Android提供了管理Activity运行状态的系统进程,其实大家别被名字迷惑了,AMS(接下来都称ActivityManagerService为AMS)其实也兼任管理其他组件运行状态。

    一、AMS概述

    1.1 AMS启动流程

    init进程是Android系统中的初始化进程,init生成Zygote进程,Android中大多数应用进程和系统进程都是通过Zygote进程生成的。


    AMS触发流程.jpg

      AMS这种系统级别的服务,一般都是在启动的时候触发,上面的流程详细地阐述了AMS的代码执行流程。由于本文并不是介绍Zygote的,所以这儿不作详细描述,可以参考一下我其他详述Zygote的文章。
      AMS启动时的代码:

    SystemServer.java
    private void startBootstrapServices() {
    //......
            mActivityManagerService = mSystemServiceManager.startService(
                        ActivityManagerService.Lifecycle.class).getService();
            mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
            mActivityManagerService.setInstaller(installer);
    //......
             mActivityManagerService.setSystemProcess();
    //......
    }
    

    其中获取AMS的地方有一点改动,去掉了AMS中的main(...)方法,将其中的工作移到AMS构造函数中。

    ActivityManagerService.java
    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();
            }
            @Override
            public void onCleanupUser(int userId) {
                mService.mBatteryStatsService.onCleanupUser(userId);
            }
            public ActivityManagerService getService() {
                return mService;
            }
        }
    

    1.2 AMS初始化工作

    从上面AMS启动流程来看,AMS在在setSystemProcess()中注册的,注册的函数就是ServiceManager. addService(Context.ACTIVITY_SERVICE, this, true);从代码中看出来,AMS是一个实名的binder server,并且在AMS还注册了很多其他的服务,例如meminfo(这是内存使用情况的server)、cpuinfo(这是CPU使用情况的server)等等,这些服务在AMS中注册启用,说明这些服务会和AMS有很多交互。

    ActivityManagerService.java
    public void setSystemProcess() {
    //......
            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));
            if (MONITOR_CPU_USAGE) {
                    ServiceManager.addService("cpuinfo", new CpuBinder(this));
            }
            ServiceManager.addService("permission", new PermissionController(this));
            ServiceManager.addService("processinfo", new ProcessInfoService(this));
    //......
    }
    

      我们查看一下AMS的构造做了什么事情,从代码中分段讲解AMS构造中要做的事情。

    ActivityManagerService.java
    public ActivityManagerService(Context systemContext) {
    //......
    //step1:
            mSystemThread = ActivityThread.currentActivityThread();
            mUiContext = mSystemThread.getSystemUiContext();
            mPermissionReviewRequired = mContext.getResources().getBoolean(
                    com.android.internal.R.bool.config_permissionReviewRequired);
            mHandlerThread = new ServiceThread(TAG,
                    THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
            mHandlerThread.start();
            mHandler = new MainHandler(mHandlerThread.getLooper());
            mUiHandler = mInjector.getUiHandler(this);
            mConstants = new ActivityManagerConstants(this, mHandler);
    //......
    //step2:
            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;
    //step3:
            mServices = new ActiveServices(this);
            mProviderMap = new ProviderMap(this);
            mAppErrors = new AppErrors(mUiContext, this);
    
    //step4:
            // TODO: Move creation of battery stats service outside of activity manager service.
            File dataDir = Environment.getDataDirectory();
            File systemDir = new File(dataDir, "system");
            systemDir.mkdirs();
            mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler);
            mBatteryStatsService.getActiveStatistics().readLocked();
            mBatteryStatsService.scheduleWriteToDisk();
            mOnBattery = DEBUG_POWER ? true
                    : mBatteryStatsService.getActiveStatistics().getIsOnBattery();
            mBatteryStatsService.getActiveStatistics().setCallback(this);
    
            mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
    
            mAppOpsService = mInjector.getAppOpsService(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);
                                }
                            }
                        }
                    });
    
            mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
    
            mUserController = new UserController(this);
    
            mVrController = new VrController(this);
    
            GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
                ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
    
            if (SystemProperties.getInt("sys.use_fifo_ui", 0) != 0) {
                mUseFifoUiScheduling = true;
            }
    //......
    //step5:
            mStackSupervisor = createStackSupervisor();
            mStackSupervisor.onConfigurationChanged(mTempConfig);
            mKeyguardController = mStackSupervisor.mKeyguardController;
            mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
            mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
            mTaskChangeNotificationController =
                    new TaskChangeNotificationController(this, mStackSupervisor, mHandler);
            mActivityStarter = new ActivityStarter(this, mStackSupervisor);
            mRecentTasks = new RecentTasks(this, mStackSupervisor);
    
    //step6:
            mProcessCpuThread = new Thread("CpuTracker") {
                @Override
                public void run() {
                    synchronized (mProcessCpuTracker) {
                        mProcessCpuInitLatch.countDown();
                        mProcessCpuTracker.init();
                    }
                    while (true) {
                        try {
                            try {
                                synchronized(this) {
                                    final long now = SystemClock.uptimeMillis();
                                    long nextCpuDelay = (mLastCpuTime.get()+MONITOR_CPU_MAX_TIME)-now;
                                    long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
                                    //Slog.i(TAG, "Cpu delay=" + nextCpuDelay
                                    //        + ", write delay=" + nextWriteDelay);
                                    if (nextWriteDelay < nextCpuDelay) {
                                        nextCpuDelay = nextWriteDelay;
                                    }
                                    if (nextCpuDelay > 0) {
                                        mProcessCpuMutexFree.set(true);
                                        this.wait(nextCpuDelay);
                                    }
                                }
                            } catch (InterruptedException e) {
                            }
                            updateCpuStatsNow();
                        } catch (Exception e) {
                            Slog.e(TAG, "Unexpected exception collecting process stats", e);
                        }
                    }
                }
            };
    
            mHiddenApiBlacklist = new HiddenApiBlacklist(mHandler, mContext);
    
            Watchdog.getInstance().addMonitor(this);
            Watchdog.getInstance().addThread(mHandler);
        }
    

      通过分析上面的代码,将AMS的构造分为6个重要的步骤:
      1.初始化构造AMS要用到的一些context和handler,例如mUiContext和mUiHandler配合使用,用于处理和UI显示相关的工作,mHandler是AMS中定义的用于分发AMS相关信息的处理器。
      2.定义了容纳前台和后台的广播队列,这也说明了AMS不仅仅关注Activity,也负责其他组件状态的管理。
      3.管理Service和Provider的对象数组。
      4.初始化system下面需要的一系列文件目录。例如权限文件、进程状态信息文件等等。
      5.这儿比较重要了,几个重要的变量需要关注一下,ActivityStackSupervisor(管理ActivityStack的重要类,这里面记录着activity状态信息,是AMS中的核心类), ActivityStarter(这是activity启动的处理类,这里管理者activity启动中用到的intent信息和flag标识,也和stack和task有重要的联系,下面会重点阐述)。
      6.启动一个线程专门跟进cpu当前状态信息,AMS对当前cpu状态了如指掌,可以更加高效的安排其他工作。

    二、Activity状态

    2.1 Activity生命周期

      Android入门必学的就是Android的四大组件,我们开发第一个app的时候,都会用到Activity,对于Activity的生命周期,大家应该已经烂熟于心了。下面是Activity生命周期状态图。


    Activity生命周期.jpg

      在这里我就不展开对生命周期的讨论了,这方面的文章还是很多的,我说一个比较重要的知识点吧,也是比较容易错的一个点,Android面试的时候,都会问这样一个问题:什么时候Activity对用户可见?这个问题相信大家都遇到过,之前看过的一些书都说是在执行onResume()的时候表明当前Activity已经可见了,这个回答可以说对,也可以说不对。因为执行onResume()的时候Activity确实可见了,但是只是这样回答不能让人满意,说明没有深入思考,也没有仔细查看源码。下面带大家看一下这一部分的源码:

    ActivityThread.java
    final void handleResumeActivity(IBinder token,
                boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    //......
            // TODO Push resumeArgs into the activity for consideration
            r = performResumeActivity(token, clearHide, reason);
            if (r != null) {
    //......
                boolean willBeVisible = !a.mStartedActivity;
                if (!willBeVisible) {
                    try {
                        willBeVisible = ActivityManager.getService().willActivityBeVisible(
                                a.getActivityToken());
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
                if (r.window == null && !a.mFinished && willBeVisible) {
                    r.window = r.activity.getWindow();
                    View decor = r.window.getDecorView();
                    decor.setVisibility(View.INVISIBLE);
                    ViewManager wm = a.getWindowManager();
                    WindowManager.LayoutParams l = r.window.getAttributes();
                    a.mDecor = decor;
                    l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                    l.softInputMode |= forwardBit;
    //......
                    if (a.mVisibleFromClient) {
                        if (!a.mWindowAdded) {
                            a.mWindowAdded = true;
                            wm.addView(decor, l);
                        } 
    //......
                    }
    
                // If the window has already been added, but during resume
                // we started another activity, then don't yet make the
                // window visible.
                } else if (!willBeVisible) {
                    if (localLOGV) Slog.v(
                        TAG, "Launch " + r + " mStartedActivity set");
                    r.hideForNow = true;
                }
    
                // Get rid of anything left hanging around.
                cleanUpPendingRemoveWindows(r, false /* force */);
    
                // The window is now visible if it has been added, we are not
                // simply finishing, and we are not starting another activity.
                if (!r.activity.mFinished && willBeVisible
                        && r.activity.mDecor != null && !r.hideForNow) {
    //......
                    if (r.activity.mVisibleFromClient) {
                        r.activity.makeVisible();
                    }
                }
    //......
            } 
    //......
        }
    

      此函数是handleResumeActivity(...),从字面上看应该是和onResume相关,在此函数中有执行activity.makeVisible(),这个makeVisible就是当前Activity可见的执行函数,所以严格来讲,不能说onResume是让Activity可见的,这点关系要搞清楚。下面Activity处理流程中详细画出了当前的Activity状态的时序图,里面也写明了Activity可见的调用时机。
      Android生命周期都是在UI线程中运行的,所以在这里面执行的代码都不能有过分耗时的情况,否则会发生ANR等问题,这个需要平时开发的时候养成良好的习惯。Android的生命周期是系统给开发者提供的一个体现当前Activity所处状态的外在体现,掌握这些生命周期,不能仅仅停留在表面的认识上,还应该知道深层的调用规律和调用逻辑。

    2.2 Activity状态管理

      Android是如何管理Activity状态的,我们平时在Android开发中用到的intent flags taskAffinity launchMode是如何管理的,一个Task包含一个或者多个Activity,一个Stack包含一个或者多个Task,这儿引入ActivityStack,还有ActivityStackSupervisor负责管理所有的Stack。那么Activity是如何创建并且如何管理的?

    2.2.1 ActivityStack创建
    ActivityStack创建过程.jpg

      从ActivityStack创建的过程中也能看出来,ActivityStackSupervisor是管理ActivityStack的重要类,操作ActivityStack,都通过ActivityStackSupervisor衍生一个接口来执行。

    ActivityStackSupervisor.java
    void setWindowManager(WindowManagerService wm) {
            synchronized (mService) {
    //......
                mHomeStack = mFocusedStack = mLastFocusedStack =
                        getStack(HOME_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
    //......
            }
        }
    
        protected <T extends ActivityStack> T getStack(int stackId, boolean createStaticStackIfNeeded,
                boolean createOnTop) {
            final ActivityStack stack = mStacks.get(stackId);
            if (stack != null) {
                return (T) stack;
            }
            if (!createStaticStackIfNeeded || !StackId.isStaticStack(stackId)) {
                return null;
            }
            if (stackId == DOCKED_STACK_ID) {
                // Make sure recents stack exist when creating a dock stack as it normally need to be on
                // the other side of the docked stack and we make visibility decisions based on that.
                getStack(RECENTS_STACK_ID, CREATE_IF_NEEDED, createOnTop);
            }
            return (T) createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop);
        }
    
        ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
            final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(displayId);
            if (activityDisplay == null) {
                return null;
            }
            return createStack(stackId, activityDisplay, onTop);
    
        }
    
        ActivityStack createStack(int stackId, ActivityDisplay display, boolean onTop) {
            switch (stackId) {
                case PINNED_STACK_ID:
                    return new PinnedActivityStack(display, stackId, this, mRecentTasks, onTop);
                default:
                    return new ActivityStack(display, stackId, this, mRecentTasks, onTop);
            }
        }
    

      初始化创建了mHomeStack(包含launcher app)、mFocusStack(接收当前即将启动的Activity)、mLastFocusedStack(接收上次启动的Activity),从代码中更好理解这些概念,下面ActivityStack分析会详细讨论这3个stack的调用时机。

    2.2.1 ActivityStack概述

    ActivityStack详细分析会在下一张讲解。本文只是简单介绍一下ActivityStack中常用的变量,这些变量对理解ActivityStack的功能有很大的帮助。
      1.定义ActivityState

    ActivityStack.java
    enum ActivityState {
            INITIALIZING,
            RESUMED,
            PAUSING,
            PAUSED,
            STOPPING,
            STOPPED,
            FINISHING,
            DESTROYING,
            DESTROYED
        }
    

      2.特殊状态下的Activity

    ActivityStack
        ActivityRecord mPausingActivity = null;
        ActivityRecord mLastPausedActivity = null;
        ActivityRecord mLastNoHistoryActivity = null;
        ActivityRecord mResumedActivity = null;
    

      mPausingActivity表示正在被暂停的Activity
      mLastPausedActivity 表示上一个被暂停的Activity
      mLastNoHistoryActivity 表示上一个设置为FLAG_ACTIVITY_NO_HISTORY的Activity
      mResumedActivity 表示当前处于恢复状态的Activity
      3.全局的ArrayList

    ActivityStack.java
        private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
        final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
        final ArrayList<ActivityRecord> mNoAnimActivities = new ArrayList<>();
    

      mTaskHistory 记录所有的Activity信息
      mLRUActivities 按照最近最少使用排序的Activity集合
      mNoAnimActivities 不考虑状态迁移动画的Activity集合

    三、Activity处理流程

    3.1 startActivity流程

      启动一个Activity之后经历的流程如图所示,这儿写明了回调各个流程的时机,其中包含这对Activity状态的处理,这一点非常重要,Android系统处理的Activity很多,我们准确指示当前Activity的状态,可以保证Activity调用的正确性。由于onPause()触发条件比较多,这边没有列出onPause()的回调流程,感兴趣的同学可以自己查看一下源码,学习一下具体的流程,但是Activity生命周期的核心要点都在onCreate() onStart() onResume()上面,其他的生命周期其实就是对Activity状态的维护。


    Activity处理流程.jpg

    应用程序的入口在什么地方?这也是面试中经常问到的问题,别告诉我你想回答是Activity.onCreate(...),那显然大错特错,所谓应用程序的入口,就是当前的应用程序所在的进程是什么时候被启动的,这才是关键。解答这个问题,不看源码,很难问答,如果只是对Activity生命周期有一个表象的认识,显然不太够。这里列出关键的地方,抛砖引玉。

    ActivityStackSupervisor.java
    void startSpecificActivityLocked(ActivityRecord r,
                boolean andResume, boolean checkConfig) {
            // Is this activity's application already running?
            ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                    r.info.applicationInfo.uid, true);
    
            r.getStack().setLaunchTime(r);
    //step1:
            if (app != null && app.thread != null) {
                try {
                    if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                            || !"android".equals(r.info.packageName)) {
                        // Don't add this if it is a platform component that is marked
                        // to run in multiple processes, because this is actually
                        // part of the framework so doesn't make sense to track as a
                        // separate apk in the process.
                        app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                                mService.mProcessStats);
                    }
                    realStartActivityLocked(r, app, andResume, checkConfig);
                    return;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting activity "
                            + r.intent.getComponent().flattenToShortString(), e);
                }
    
                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
    //step2:
            mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                    "activity", r.intent.getComponent(), false, false, true);
        }
    

    上面标注了step1和step2,从step1的判断来看if (app != null && app.thread != null),说明当前的Activity所在的进程存在的话,执行realStartActivityLocked(...),那么step2执行的条件显然就是当前Activity所在的进程不存在的情况了。继续看下去。


    Activity启动入口.jpg

    很显然,ActivityThread->main(...)才是应用程序真正的启动入口。仔细阅读源码能帮助我们什么?能帮助我们透过现象看本质。

    相关文章

      网友评论

        本文标题:ActivityManagerService架构剖析开篇

        本文链接:https://www.haomeiwen.com/subject/ykspuftx.html