Android7.1 ActivityManagerService概述

简介

        ActivityManagerService(以下简称:AMS)是android系统的一个系统服务,是应用进程的管理服务端,直接的控制了应用程序的各个行为,保证了系统中不同的应用程序之间能够和谐的合理的进行调度运行。AMS主要的职责就是对Android四大组件(Activity,Service,ContentProvider,Broadcast)进行管理。虽然开发者在开发过程中会经常的使用到AMS提供的一些功能,但是可能很少有机会对它进行一个统一的整体和认知。

该文档的书写目的主要是为了对做AMS进行了一个整体的基础介绍和讲解,希望能够一些开发人员有所帮助。

系统服务启动过程

如下图所示,该图概要描述了系统启动时的整个过程:


1) 系统启动时,会先启动kernel模块

2) kenel模块中会启动init进程,而init进程会解析init.rc文件并启动一系列native服务。

3) Zygote进程预加载和初始化一些核心类库,便于之后的应用进程的代码共享。

4) Zygote启动(fork)系统服务进程system_server

5) System_Server进程中会发布一系列的系统服务,而AMS就是其中之一,并在之后的生命周期中运行在system_server的进程中。

6) AMS启动(fork)出一系列的应用进程。

详细的系统服务启动流程请参考《Android启动系列文章

AMS框架设计

结构框架设计

      AMS是android上层系统最核心的模块之一,其主要的工作是对所有的应用进程及其进程中的四大组件进行管理。(当然这里面也涉及了一些window、电源、权限等内容, 我们这里不再讲述)

对进程的管理包括:进程的创建与销毁、进程的优先级调整。

对组件的管理包括:Activity的调度管理、Service的管理、Broadcast的分发、以及ContentProvider管理。

通信框架设计

      从上节我们可以得知,AMS作为上层最核心的模块之一,不论是直接对进程的管理还是对进程中组件的调度管理,它都离不开和应用进程之间的通信。而在Android系统中,最常用的进程间的通信手段就是使用Binder调用的方式,AMS和应用进程之间的通信方式也正是采用的Binder机制。


      AMS和应用之间的通信过程中有两个非常重要的类:ActivityManagerService和ActivityThread。其中ActivityThread是应用进程的入口,负责管理进程主线程的执行,根据AMS的调度要求直接的控制着应用进程中各个组件的有序执行。

       这里需要注意的是:应用对AMS的通信都是最终通过ActivityManagerProxy直接访问的AMS。而AMS向应用的通信,则需要通过ApplicationThread然后将异步消息通过Handler发送到应用的主线程中执行。

AMS初始化

AMS属于系统核心进程,是从SystemServer进程中启动起来的。

构造函数

     在AMS构造函数中做一些最基本的初始化工作,如初始化异步线程作为AMS的“主线程”,建立广播的分发队列等。

    public ActivityManagerService(Context systemContext) {
        mContext = systemContext;            //设置系统上下文context
        mFactoryTest = FactoryTest.getMode(); //获取工厂测试模式
        mSystemThread = ActivityThread.currentActivityThread();  //获取当前的系统线程

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

        mHandlerThread = new ServiceThread(TAG,
                android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
        mHandlerThread.start();    //创建一个线程
        mHandler = new MainHandler(mHandlerThread.getLooper()); //使用新创建线程的Looper创建hander
        mUiHandler = new UiHandler();   //使用主线程的Looper创建显示UI的handler

        /* 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());   //创建hander用来杀进程
        }

        mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
                "foreground", BROADCAST_FG_TIMEOUT, false); //创建前台广播队列,广播处理超时时间为10s
        mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
                "background", BROADCAST_BG_TIMEOUT, true);  //创建后台广播队列,广播超时时间为60s
        mBroadcastQueues[0] = mFgBroadcastQueue;
        mBroadcastQueues[1] = mBgBroadcastQueue;

        mServices = new ActiveServices(this);   //创建Service对象
        mProviderMap = new ProviderMap(this);   //管理Provider
        mAppErrors = new AppErrors(mContext, this); //处理应用错误

        // TODO: Move creation of battery stats service outside of activity manager service.
        File dataDir = Environment.getDataDirectory();  //获取系统data/路径
        File systemDir = new File(dataDir, "system");   //获取data/system路径
        systemDir.mkdirs();                             //创建文件夹
        mBatteryStatsService = new BatteryStatsService(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 = 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);
                            }
                        }
                    }
                });

        mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));

        mUserController = new UserController(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;
        }

        mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));

        mConfiguration.setToDefaults();
        mConfiguration.setLocales(LocaleList.getDefault());

        mConfigurationSeq = mConfiguration.seq = 1;
        mProcessCpuTracker.init();

        mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
        mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
        mStackSupervisor = new ActivityStackSupervisor(this); //Activity stack信息的管理者
        mActivityStarter = new ActivityStarter(this, mStackSupervisor);  //启动Activity的类
        mRecentTasks = new RecentTasks(this, mStackSupervisor);  //最近任务

        mProcessCpuThread = new Thread("CpuTracker") {  //获取cpu信息的线程
            @Override
            public void run() {
                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);
                    }
                }
            }
        };

        Watchdog.getInstance().addMonitor(this);  //将AMS添加到watchdog的检测列表,每三十秒检测一次关键区,60s无相应杀死系统
        Watchdog.getInstance().addThread(mHandler); //注册主线程,详细watchdog机制参考之前文章

        mIsFreqAggrEnabled = mContext.getResources().getBoolean(
                   com.android.internal.R.bool.config_enableFreqAggr);

        if(mIsFreqAggrEnabled) {
           lFreqAggr_TimeOut = mContext.getResources().getInteger(
                   com.android.internal.R.integer.freqaggr_timeout_param);
           lFreqAggr_Init_ParamVal = mContext.getResources().getIntArray(
                   com.android.internal.R.array.freqaggr_init_param_value);
           lFreqAggr_ParamVal = mContext.getResources().getIntArray(
                   com.android.internal.R.array.freqaggr_param_value);
        }

        mIsLaunchBoostv2_enabled = mContext.getResources().getBoolean(
                   com.android.internal.R.bool.config_enableLaunchBoostv2);

        if(mIsLaunchBoostv2_enabled) {
           lBoost_v2_TimeOut = mContext.getResources().getInteger(
                   com.android.internal.R.integer.lboostv2_timeout_param);
           lBoost_v2_ParamVal = mContext.getResources().getIntArray(
                   com.android.internal.R.array.lboostv2_param_value);
        }
    }

initPowerManagement

     在初始化power相关内容时,主要是创建PARTIAL_WAKE_LOCK,在系统做一些操作时保证cpu唤醒状态,并获取PowerManger相关类。

    public void initPowerManagement() {
        mStackSupervisor.initPowerManagement();  
        mBatteryStatsService.initPowerManagement();
        mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class);
        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
        mVoiceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*voice*");
        mVoiceWakeLock.setReferenceCounted(false);
    }

setSystemProcess

       初始化发布一些服务信息。如:meminfo、dbinfo、cpuInfo等,并创建system进程的ActivityThread并设置一些基本进程信息。发布meminfo、dbinfo、cpuInfo等服务是为了能够对设备情况进行实时的dump操作。

    public void setSystemProcess() {
        try {
            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));

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

            synchronized (this) {
                ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);//创建系统进程信息
                app.persistent = true;  //设置系统进程持久化属性为true
                app.pid = MY_PID;       //设置pid
                app.maxAdj = ProcessList.SYSTEM_ADJ;   //最大adj为-900,系统进程
                app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
                synchronized (mPidsSelfLocked) {
                    mPidsSelfLocked.put(app.pid, app);
                }
                updateLruProcessLocked(app, false, null);  //更新lru列表
                updateOomAdjLocked();                      //更新oom优先级
            }
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(
                    "Unable to find android system package", e);
        }
    }

installSystemProviders

初始化系统的db和Provider。

    public final void installSystemProviders() {
        List<ProviderInfo> providers;
        synchronized (this) {
            ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);  //获取系统进程信息
            providers = generateApplicationProvidersLocked(app);  //根据进程信息,从PMS中获取对应Providers信息
            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) {
            mSystemThread.installSystemProviders(providers);  //安装系统Provider
        }

        mCoreSettingsObserver = new CoreSettingsObserver(this);
        mFontScaleSettingObserver = new FontScaleSettingObserver();

        //mUsageStatsService.monitorPackages();
    }

setWindowManager

    public void setWindowManager(WindowManagerService wm) {
        mWindowManager = wm;   //将在SystemServer中创建的wms设置进AMS,可以在AMS中向WMS通信。
        mStackSupervisor.setWindowManager(wm);  //wms设置到ActivityStackSupervisor
        mActivityStarter.setWindowManager(wm);   //wms设置到ActivityStarter
    }

systemReady

当系统准备完成后就会调用AMS的systemReady函数来启动关键进程,如systemUI,home,phone等。

    public void systemReady(final Runnable goingCallback) {
    ...........
        Slog.i(TAG, "System now ready");
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
            SystemClock.uptimeMillis());

          ........
        if (goingCallback != null) goingCallback.run();  //回调回SystemServer中启动其他进程
         .......
            // Only start up encryption-aware persistent apps; once user is
            // unlocked we'll come back around and start unaware apps
            startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);  //启动系统持久化应用

            startHomeActivityLocked(currentUserId, "systemReady");    //系统Home应用
           .........
    }

应用进程启动

Android系统中所有的应用进程的创建和启动都是在AMS中完成的。正常来说一个进程的启动有六种可能的原因:

1) 需要启动Activity时

2) 需要接收Broadcast时

3) 需要启动Service时

4) ContentProvider被访问时

5) 常驻内存进程自动重启或刚开机AMS主动启动时

6) 进行数据备份时


         上图是一个进程进行启动的流程,应用进程的入口都是位于ActivityThread的main方法中。当AMS去请求fork一个应用进程的时候,ActivityThread中的main方法将会被调用,而且就直接的运行在了fork出来的进程中。

         而这个时候,AMS其实只知道该进程的一个pid和uid以及进程名称等信息,并没有这个进程的binder句柄,很明显这个时候AMS是不能向应用进程进行通信的,而应用进程只是知道自己的名称等简单信息,但是具体要干些什么它却是不知道的。

       所以这个时候就需要应用进程先主动的将自己的binder句柄注册给AMS,这就是attachApplication的过程。而AMS拿到应用进程的binder句柄后就开始向其通信,绑定一些进程的必要信息,而这就是bindApplication的过程。

Activity管理

        对Activity的管理是AMS中最重要也是最复杂的部分,因为Activity扮演着用户和UI界面交互的接口,最直接的影响着用户的体验和感受。

        正是因为Activity所扮演的角色,使得Activity承担了大量的显示和交互工作。一个应用可以有多个Activity,而这些Activity可以启动其他应用程序的Activity(想要使用其他应用程序中已经拥有的功能)进行数据交互,这样就势必牵扯到多个应用的多个Activity的管理。

        而如何能使得这些不同应用间的Activity可以正常高效的进行交互工作而不至于出现混乱呢? Task的提出很好的解决了这个问题。

Task

     这是Android系统中设计的一种栈机制(在AndroidL中对应的数据结构为TaskRecord),用于管理一组拥有相关联任务的Activity。其遵循着后进先出的原则,系统总是显示位于栈顶的Activity。


      一个Task任务中的所有Activity是一个有机的整体,用户可以通过启动一个新的Task或者通过退回到Home操作将它整体的移动到后台(background),这时后台Task中的Activity将全部处于stop状态。而前台Task中的Activity将处于start状态(其中前台Activity处于resume状态)。


      从上面两图的介绍我们可以知道,Task的栈机制对于大多数的应用基本都能够满足他们的需求,但是也存在一些特殊的情况,如应用想将启动一个新的Task去运行将要启动的Activity,而不是在已经存在的Task中去启动。


allowTaskReparenting 用来标记一个activity实例在当前应用退居后台后,是否能从启动它的那个task移动到有共同affinity的task,默认值为false。 

clearTaskOnLaunch 这个属性用来标记是否从task清除除root activity之外的所有的activity,默认为“false”。该属性也只对根Activity起作用,其他的Activity都会被忽略。 

alwaysRetainTaskState 用来标记应用的task是否保持原来的状态,默认为“false”。该属性只对root activity起作用,其他的会被忽略。 默认情况下,如果一个应用长时间的呆在后台,用户从主选单再次进入该应用时,系统就会对该应用的task进行清理,除了root activity,其他Activity都会被移除掉,但是如果在根Activity中设置了此属性之后,用户再次启动应用时,仍然可以看到上一次操作的界面。 

finishOnTaskLaunch 这个属性和android:allowReparenting属性相似,不同之处在于allowReparenting属性是重新宿主到有共同affinity的task中,而finishOnTaskLaunch属性是销毁实例。

       Task的概念在AMS中对应的数据结构叫做为TaskRecord,它是通过自身结构中的一个ArrayList对栈中的所有Activity进行管理。

final class TaskRecord {
	........................................
    /** List of all activities in the task arranged in history order */
    final ArrayList<ActivityRecord> mActivities;
    /** Indication of what to run next when task exits. Use ActivityRecord types.
     * APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
     * task stack. */
    private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
	........................................
}

从上面TaskRecord的定义中我们还可以看到有一个比较重要的变量mTaskToReturnTo,主要涉及到按back返回到哪个界面。

Stack

        由于系统中可以存在很多个Task,所以这些Task要如何进行调度也需要进行统一的管理,于是AMS中就定义了另外的一个概念Stack(在AndroidL之后对应的数据结构为ActivityStack),其作用就是用于对不同的Task进行管理,同样采用的是后进先出的栈机制原则,从而间接的达到对Activity管理的目的。

      AMS中的Stack有多个,我们经常用到的有两个,一个属于home stack,里面包括systemui的相关activity。另外一个application stack,包括了除home和systemui之外的所有进程的Activity。其余的stack主要与多窗口相关

        /** Invalid stack ID. */
        public static final int INVALID_STACK_ID = -1;

        /** First static stack ID. */
        public static final int FIRST_STATIC_STACK_ID = 0;

        /** Home activity stack ID. */
        public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;

        /** ID of stack where fullscreen activities are normally launched into. */
        public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;

        /** ID of stack where freeform/resized activities are normally launched into. */
        public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;

        /** ID of stack that occupies a dedicated region of the screen. */
        public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;

        /** ID of stack that always on top (always visible) when it exist. */
        public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;

        /** Last static stack stack ID. */
        public static final int LAST_STATIC_STACK_ID = PINNED_STACK_ID;

       每一个Stack都可以有若干的Task,但是因为不同应用的Task位于同一个Stack中,那么对应的Task退出后结果是显示home呢还是继续显示上一个Task中的top activity呢?TaskRecord中的mTaskToReturnTo给了我们答案:

APPLICATION_ACTIVITY_TYPE                                显示上一个Task
HOME_ACTIVITY_TYPE                                 显示home应用
RECENTS_ACTIVITY_TYPE                              显示RecentActivity

启动流程

      从上面的介绍我们可以知道,Activity的启动会出现Activity之间的交互,详细的调用过程的流程图如下,需要说明的是AMS会先对当前的Activity进行pause,然后才去执行目的Activtiy的launch操作。


详细的应用启动流程后文详细分析。

Broadcast管理

      在Android系统中,广播是在组件之间传递数据(通过Intent)的一种机制,这些组件甚至是可以位于不同的进程中,从而起到了进程间数据传递的作用。广播是Framework层对观察者模式的一种运用。

      使用广播的好处在于广播的发送者和接收者之间事先是不需要知道对方的存在的,从而保证了各系统之间的低耦合。这样各系统之间就具有了较高的扩展性,容易与其他的系统进行集成。

广播类型分析

      广播发送的接口有很多,如图所示,但是不论是哪种方式发送的广播其在AMS中的处理流程是一致的,都会先进行foreground/background的区分,然后再进行parallel/ordered的区分。


      广播的发送者和接收者之间是一对多的关系,如图所示,一个广播在AMS中对应的数据结构是BroadcastRecord,而广播的类型处理流程其实就是将BroadcastRecord加入到对应的类型队列中的过程。

所以广播按照不同的方向划分,可以分为不同的类型:


前台广播与后台广播

      在AMS在其构造方法中定义了两个广播接收队列,mFgBroadcastQueue和mBgBroadcastQueue,他们分别对应着前台广播和后台广播。 而AMS将会把对应的将要发送的广播进行区分放到对应的队列中。

       前台广播和后台广播是以Intent中携带的flag数据(FLAG_RECEIVER_FOREGROUND)进行区分的,只有Intent中添加了这样的Flag数据的广播才是一个前台广播,否则即为后台广播。所以前台广播与后台广播的划分依据是根据发送方发送的数据来决定的。

     除了超时时间上的不同外,前台广播和后台广播还有一个很重要的区别,即:是否会受到后台Service的影响,这个问题在后面会讲到。

有序广播和并行广播

       不论是前台广播队列(mFgBroadcastQueue)亦或是后台广播队列(mBgBroadcastQueue),他们都分别会包含Parallel和Ordered两个列表队列,而广播实际上最终就是被加入到了对应队列中的这两个列表中。

而有序广播和并行广播的划分依据不仅是发送方的发送方式,还要看接收方的注册方式。

综上所述,Broadcast的类型处理应该是如下图所示的一个流程:


      但是需要注意的一点是,广播的发送者和接收者是一对多的关系,而不同的接收者可以有不同的注册方式(静态注册和动态注册),这也就造成了一个广播发送出来可能既要在并行队列中处理一部分的接收者,也要在有序队列中处理另外的一部分接收者。


既然有序广播和并行广播的分类即受发送方影响,也受接收方影响,那我们来看下到AMS中的逻辑具体是如何进行判断的:

Sticky广播

        Stick广播是一种比较特殊的广播,其分发方式最终也是按照有序广播或无序广播的方式进行分发,而不同的是这个类型的广播Intent在经过AMS并分发出去之后并不会被丢弃,而是会被AMS记录并保存,每当有对应的新的接收者向AMS进行注册的时候,AMS都会立即将对应的Intent数据给分发出去。

广播的分发流程

有序广播分发流程

       AMS对于有序广播的分发可以看成是一个同步的过程,同一个广播只有在前一个接收者处理完成之后,下一个接收者才可以进行处理。只有前一个广播被分发并处理完成之后,下一个的广播才能被分发。过程如下图所示:


详细的时序图如下:

并行广播分发发流程

      与上述有序广播的分发不同,并行广播的分发可以看成是一个异步的过程,同一个广播的接收者可以同时都去处理这个广播。通过上述的表格,我们可以知道,只有动态进行注册的receiver才可能接收这样的并行广播。


详细的时序图如下:


优先级

       需要注意的是,不同的广播之间是没有优先级顺序的,都是按照队列的顺序进行分发。但是同一个广播的不同接收者之间却是可以存在的,而在广播的分发过程中,AMS始终会先分发给优先级较高的接收者,而同一个优先级的接收者的分发顺序要看PackageManager中对AndroidManifest的遍历扫描了。

延迟处理

      前面我们提到了前台广播和后台广播的一个很重要的区别就是是否会受到后台service的影响。基于性能上的考虑,google对后台有序广播和后台服务进行了重新设计,后台有序广播的发送要受到同userId下的后台服务的影响。

      AMS规定上一个receiver处理完成之后,如果对应的广播整个被处理完成或者下一个receiver位于其他的进程中时,AMS就会检测同一个userId下是否存在后台服务,如果存在就停止分发广播的分发流程,直到这些后台服务执行结束时才可以继续分发流程。

            // Don't do this if the next receive is in the same process as the current one.
            if (receiver == null || nextReceiver == null
                    || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
                    || !receiver.processName.equals(nextReceiver.processName)) {
                // In this case, we are ready to process the next receiver for the current broadcast,
                // but are on a queue that would like to wait for services to finish before moving
                // on.  If there are background services currently starting, then we will go into a
                // special state where we hold off on continuing this broadcast until they are done.
                if (mService.mServices.hasBackgroundServices(r.userId)) {
                    Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());
                    r.state = BroadcastRecord.WAITING_SERVICES;
                    return false;
                }
            }

当后台服务执行完后就会调用BroadcastQueue的backgroundServicesFinishedLocked函数,重新开始执行广播。

    public void backgroundServicesFinishedLocked(int userId) {
        if (mOrderedBroadcasts.size() > 0) {
            BroadcastRecord br = mOrderedBroadcasts.get(0);
            if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
                Slog.i(TAG, "Resuming delayed broadcast");
                br.curComponent = null;
                br.state = BroadcastRecord.IDLE;
                processNextBroadcast(false);
            }
        }
    }

Service管理

Service是一个应用程序的组件,可以比较长时间的运行在后台,它不提供给用户交互界面,

即使一个应用程序已经退到后台,它所运行的服务也不会受到影响,而会继续在后台进行运行。另外,一个应用程序可以启动另一个应用程序的服务或者是直接绑定另一个应用进程的服务直接的进行进程间通信。

让我们先来看一下Service的两种启动方式有什么不同:

Service启动

从上图可以看出,不同的启动方式会使得Service的生命周期变的不同,而我们要学会在适当的场景下恰当的去启动一个Service。

startService

通常我们会在一个应用组件中去启动一个service服务,比如Activity。一旦Service被这样的方式启动后,其将会独立的存在而不会继续依赖于它的启动者。在之后的整个生命周期中它们也不会再有任何的交互。

直到Service中的操作处理完成后,需要调用stop操作将其结束掉。

onStartCommand方法是该启动方式下的一个很重要的生命周期,它有几个很关键的返回值:

返回值

描述

START_NOT_STICKY 当该服务进程被系统给杀掉后,该服务不会重新的建立并启动。该返回值可以防止一些不必要进程因为一个服务而被反复的启动。
START_STICKY 当该服务进程被系统给杀掉后,该服务会重新的进行启动,同时也会将其所在进程也给启动起来。而启动服务的Intent参数为null。
START_REDELIVER_INTENT 当该服务进程被系统给杀掉后,该服务会重新的进行启动,同时也会将其所在进程也给启动起来。而启动服务的Intent参数为被杀之前的Intent。

bindService

与上述的使用场景不同,bindService操作通常是需要和Service进行进程间通信时才使用。而Service就像是一个C/S架构中的服务端,其他组件(比如 Activity)绑定到它后可以向它发送请求,可以接受从它返回的响应,甚至直接进行进程间通信(IPC)。

而一个Service如果想要被其他的组件进行绑定,那么它就必须要实现自身的onBind方法,并且返回一个IBinder对象,其他组件也只有拿到这个组件后才能和Service进行IPC通信。

一个Service可以有多个client,并且其onBind方法只会执行一次,所有的client拿到的IBinder都是同一个对象的句柄,并且只有在所有的客户端都unbind操作后,Service才会被销毁。

前台service和后台Service

前台Service和后台Service其实是Service对自身进程级别的一个调整过程。也就是说前台服务和后台服务并不是固定不变的,两者是可以根据需要进行转化的。

类型

影响

超时

前台Service

进程优先级相对较高

20*1000

后台Service

---

200*1000

需要注意的是,Service虽然可以长时间的运行在后台,并不意味着我们可以盲目的将一些耗时操作放入到其中进行处理,因为这里我们说到的后台指的是其不提供UI界面,但其实质上还是运行在主线程中的。

ContentProvider管理

Provider的设计思路

1:安全性  

2:独立性  

3:封装性 

4:跨进程

注* ContentProvider作为一种数据共享的方式,其实质实际上是一个数据传输的通道,在Service端将要进行访问的数据按照一定的格式进行封装后再返回给客户端,或者是客户端将数据按照一定的规则传递给服务端进行处理。所以ContentProvider的服务端并不是必须使用数据库进行实现的,我们只要将对应的数据封装成一个Cursor进行返回也能达到同样的目的。

AMS对ContentProvider管理主要涉及到其发布(publish),安装(install)和查找(query)。

Install和publish


Query


进程管理

      当一个程序第一次进行启动的时候,Android会为其创建一个Linux进程和一个线程(main)进行运行。默认情况下所有该程序的组件都将在该线程下运行。不同与Linux的进程管理策略,为了提高进程的启动响应速度,Android会尽量的保留一个正在运行的进程,只会在内存资源不足时才去尝试停止甚至是杀掉一些进程便于释放响应的资源,以保证用于正在访问的当前进程拥有足够的资源去及时的响应用户事件。

Android杀进程之前会判断进程的重要程度,按照从高到低将进程划分为5个级别(这5个级别也可以称为进程的生命周期):

 Foreground process

也称前台进程,说明该进程正在和用户进行交互,通常有以下行为的都属于前台进程:

1:进程中存在一个Activity处于resume状态,并且正在和用户进行直接的交互。

2:进程中存在一个Service被绑定到一个前台Activity上,并且正在和用户进行交互。

3:进程中存在一个Service是一个前台Service(调用了startForeground方法)。

4:进程中存在一个Servcie正在执行自己的生命周期(如:onCreate,onStart......)。

5:进程中存在一个BroadcastReceiver正在执行自己的生命周期(如:onReceive)。

通常情况下,Android系统任何时候都是存在前台进程的,它们基本上不会被杀掉。但是如果当时设备的资源情况异常的糟糕,以至于这些前台进程无法继续运行,那么系统也是可以将其给kill掉的作为资源释放的最后手段,从而保证前台进程持续的维持用户界面的响应。

Visible process

也称可见进程,该级别的进程没有前台组件(如:前台进程中的1至5),但是却能够影响用户的可见性,通常有以下行为的都属于可见进程:

1:进程中存在一个Activity处于pause状态(即:还是可见状态)。

2:进程中存在一个Service并绑定到了可见进程或前台进程的Activity上。

可见进程也是一中非常重要的进程,系统通常是不会杀掉它们的,除非是为了保证前台进程的正常运行但是又没有其他级别的进程可以杀掉。

Service process

也称服务进程,进程中存在一个Service是以startService开始运行的,并且不属于更高的级别。尽管服务进程不会被用户直接的看到,但是却是用户比较关心的和系统功能直接息息相关的服务(如:音乐播放器的播放服务Service,下载管理的Service,数据的网络同步Service等...)

Background process

也程后台进程,该类进程通常是指哪些不会对用户体验造成任何影响的进程,系统可以随时的杀掉他们来进行资源的释放。正常情况下,系统中的后台进程是比较多的,由于Android系统的内存管理策略,这些进程也都被保存在了LRU(least recently used)对列中。

Empty process

也称空进程,该类进程中没有持有任何活跃的应用组件,不会有任何的数据运行,系统保留该进程的唯一原因是为了做缓存目的,提高组件启动时的速度。故该进程是最应该被最先杀掉的。 

从上述的进程分类,我们可以知道,进程的优先级和应用组件是紧密相关的,而AMS会根据应用组件的运行执行实时的对应用进程的优先级进行适当的调整,保证各进程在能够流畅运行的前提下,尽量的不影响用户体验并提高应用的性能。

Low Memory Killer

基本原理:

Android的low memory killer是linux的基础上修改而来的一种内存管理机制,当系统内存不足时,杀掉重要性较低的进程以释放其内存。进程的选择有两个依据:oom_adj和占用的内存大小。

oom_adj:代表进程的优先级,优先级越高的进程其oom_adj值越小,反之则越大。

每一个oom_adj都会有一个空闲内存的阀值与之对应,而kernel每隔一段时间都会对空闲的内存进行检查,如果空闲内存低于某个阀值的时候,则会杀掉oom_adj最大的那么进程,如果存在同样的oom_adj的时候,则会先杀掉暂用内存最多的那个进程。

Lowmemkiller的位置

kernel/drivers/staging/android/lowmemorykiller.c

查看进程的优先级oom_adj的方法:

adb shell cat proc/进程号/oom_adj

AMS的进程管理

Ams在进程管理中起到的作用就是为了low memery kill的实现进行服务。AMS会在各个应用进程的活动组件运行的过程中实时的进行动态的调整进程的oom_adj值,并通过socket(lmkd)最终传递给kernel。(参见:具体applyOomAdjLocked方法

Ams中对进程的管理还涉及到另外的一个问题,就是对进程中线程组(process group)的调整,这个调整也是实时的伴随着应用进程中活动组件的调整而动态的进行者调整。而该进程组的调整也关系到进程是否会直接的被Ams给杀掉。

参数 描述
THREAD_GROUP_DEFAULT 组内的每个线程依赖其自身的优先级,并且优先级小于THREAD_PRIORITY_BACKGROUND(10)的线程将自动被移动到前台线程组。
THREAD_GROUP_BG_NONINTERACTIVE                                 组内的所有线程都减小占用CPU时间片
THREAD_GROUP_FOREGROUND 组内的所有线程都正常占用CPU时间片(AMS其实并未用到这个参数)

以上三个参数是AMS要进行进程的线程组设置的三个值,但是其实在整个应用进程的生命周期过程中并没有真正的使用foreground类型,而都是在default和background类型之间相互转换。

AMS在bindApplication的时候都会设置进程的线程组为default,但是在oom_adj进行计算的时候设置为默认值background。然后根据应用进程活动组件的执行情况和进程的oom_adj去综合计算设置对应的线程组类型。(参见:具体computeOomAdjLocked方法

而ams中的kill进程操作(如从recent list中进行移除),也只有在线程组为background的时候才会去真正的执行,否则只是设置一个kill标记等待线程组变为background的时候才真正的去进行kill操作。

猜你喜欢

转载自blog.csdn.net/fu_kevin0606/article/details/79748015