AMS 深入了解(一、进程管理)(and5.1)

Android应用程序的载体是APK文件,它是一个组件和资源的容器。APK文件和我们常见的执行文件还是有区别的:每个执行文件都是运行在一个进程中,但是APK可能运行在一个进程中,也可能和其他APK运行在一个进程中。Android的设计理念中弱化进程的存在,而是以组件的概念代替。

但是Android毕竟是建立在Linux,基础的环境还是由进程组成。

一、应用进程的组成

Android应用的核心类是ActivityThread类,mActivityies,mServices、mProviderMap3个变量的类型都是ArrayMap,保存有了应用中所有的Activity、Service、ContentProvider。没有BroadcastReceiver,应用广播的生命周期比较短,属于调用一次运行一次的类型。

mInitialApplication变量是一个Application对象,应用中Application对象只有一个。如果每个应用从Application类派生了自己的类,mInitialApplication对象将是应用中自定义的实例对象。

ApplicationThread类型的变量mAppThread是一个Binder实体对象,AMS通过它来调用应用的接口。

mPackages和mResourcePackages保存的是应用apk包的信息。这里有两个变量的原因是appliction属性中,有hascode属性。如果不包含代码,只有资源文件的保存在mResourcePackages相反保存在mPackages。

1.1 ApplicationThread

ApplicationThread是ActivityThread的一个嵌套类。它不是一个Thread,是一个Binder的服务类。AMS及时通过Binder调用ApplicationThread里面的接口。

ApplicationThread继承ApplicationThreadNative,而ApplicationThreadNative又是继承Binder。对应的客户端的Binder是IApplicationThread,是在AMS中。

比如说在ApplicationThread中调用scheduleResumeActivity,最后会发送一个消息。

        public final void scheduleResumeActivity(IBinder token, int processState,
                boolean isForward, Bundle resumeArgs) {
            updateProcessState(processState, false);
            sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0);
        }

最终消息处理会去调用handleResumeActivity函数。

                case RESUME_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
                    handleResumeActivity((IBinder) msg.obj, true, msg.arg1 != 0, true);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

知道这流程后,我们就知道AMS调用schedule。。。函数,最总都睡调到handle。。。函数。

1.2 Context

Context的字母意义是上下文环境。应用上层代码都是通过Context类提供的接口来操作Android的4大组件和资源的。

Context的实现类是ContextWrapper类,它其中有一个成员mBase,是ContextImpl类,这是一个典型的代理模式,好多功能都在ContextImpl实现。

而且为了方便,Service、Application、Activity都是ContextWrapper的子类。

二、AMS服务

AMS是AndroidFramework的核心,管理着四大组件。

AMS是Binder服务,但是不是通过AIDL自动生成的。AMS从ActivityManagerNative类派生,这个类实现了IActivityManager的接口。然后还有一个内部类ActivityManagerProxy,这个是应用ActivityManager调用过来的。相当于AMS的客户端Binder

一般ActivityManager中都是通过下面的方法,来获取AMS的Binder客户端

ActivityManagerNative.getDefault()
    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

2.1 AMS的初始化

AMS运行在SystemServer进程中:

        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);

AMS的构造函数就是初始化一些成员变量,然后建一个消息处理handler等,这边就不分析了。

SystemServer中创建了AMS后,调用了其setSystemProcess

    public void setSystemProcess() {
        try {
            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);//注册一些Service
            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));

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

            synchronized (this) {
                ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);//将SystemServer进程加入管理
                app.persistent = true;
                app.pid = MY_PID;
                app.maxAdj = ProcessList.SYSTEM_ADJ;
                app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
                mProcessNames.put(app.processName, app.uid, app);
                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);
        }
    }

在这个函数中,将一些Service注册到ServiceManager,并且最后把SystemServer加入到process的管理中。

2.2 systemReady方法

SystemServer启动完所有服务后,将调用AMS的systemReady方法。systemReady方法比较长,我们就挑一些重点说。

        ArrayList<ProcessRecord> procsToKill = null;
        synchronized(mPidsSelfLocked) {
            for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
                ProcessRecord proc = mPidsSelfLocked.valueAt(i);
                if (!isAllowedWhileBooting(proc.info)){//检查进程是否有persistent标志
                    if (procsToKill == null) {
                        procsToKill = new ArrayList<ProcessRecord>();
                    }
                    procsToKill.add(proc);
                }
            }
        }
        
        synchronized(this) {
            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;
        }

这段代码作用是找到已经启动的应用进程,然后杀掉它们。目的是为了在启动HOME前准备一个干净的环境。但是有一种进程不用退出,isAllowWhileBooting方法会判断进程是否带有FLAG_PERSISTENT标记,如果有就不用退出了。因为有这个标记还要启动它们的,这里就留下不清理了。

        synchronized (this) {
            if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {//不在测试模式
                try {
                    List apps = AppGlobals.getPackageManager().
                        getPersistentApplications(STOCK_PM_FLAGS);//检查系统中带有FLAG_PERSISTENT标志的应用
                    if (apps != null) {
                        int N = apps.size();
                        int i;
                        for (i=0; i<N; i++) {
                            ApplicationInfo info
                                = (ApplicationInfo)apps.get(i);
                            if (info != null &&
                                    !info.packageName.equals("android")) {
                                addAppLocked(info, false, null /* ABI override */);//启动应用
                            }
                        }
                    }
                } catch (RemoteException ex) {
                    // pm is in same process, this will never happen.
                }
            }

            // Start up initial activity.
            mBooting = true;
            startHomeActivityLocked(mCurrentUserId, "systemReady");//启动HOME应用
............
        }
    }

这段代码主要启动带有FLAG_PERSISTENT标志的应用,然后启动HOME应用,启动后会发出ACTION_BOOT_COMPLETED广播。

从systemReady方法可以知道:

1.系统应用如果响应ACTION_PRE_BOOT_COMPLETED,可以在升级后得到通知。

2.如果系统应用希望在HOME应用启动前启动,可以加入FLAG_PERSISTENT标志。接受Intent的ACTION_BOOT_COMPLETED的应用只能在HOME启动后启动。

2.3 Process管理

虽然Android的应用开发中,不再强调进程的概念。但是在AMS中,还必须管理和调度进程。AMS对进程的管理,主要在两个方面:

一、动态地调整进程在mLruProcess列表中的位置。

二、调整进程的oom_adj值。

这两项调整和系统进行自动内存回收有关,当内存不足时,系统会关闭一些进程来释放内存。系统就是根据oom_adj值来杀进程。值越大越可能被杀。

下面我们看下如何启动进程

在上面一节中,把带有FLAG_PERSISTENT标志的应用放进addAppLocked就可以启动应用,我们来看下这个函数:

    final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
            String abiOverride) {
        ProcessRecord app;
        if (!isolated) {//该值为true,表示要启动一个新的进程
            app = getProcessRecordLocked(info.processName, info.uid, true);
        } else {
            app = null;
        }

        if (app == null) {
            app = newProcessRecordLocked(info, null, isolated, 0);//创建一个ProcessRecord对象
            mProcessNames.put(info.processName, app.uid, app);
            if (isolated) {
                mIsolatedProcesses.put(app.uid, app);
            }
            updateLruProcessLocked(app, false, null);
            updateOomAdjLocked();
        }

        // This package really, really can not be stopped.
        try {
            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&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
                == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
            app.persistent = true;
            app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
        }
        if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
            mPersistentStartingProcesses.add(app);
            startProcessLocked(app, "added application", app.processName, abiOverride,//启动进程
                    null /* entryPoint */, null /* entryPointArgs */);
        }

        return app;
    }

这个方法会根据isolated来决定是否要启动一个进程,getProcessRecordLocked方法会在当前运行的进程列表中查找进程。updateLruProcessLocked和updateOomAdjLocked方法后面介绍。下面再来看看startProcessLocked方法:

    private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
.......            
			Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);
            checkTime(startTime, "startProcess: returned from zygote!");
.......
            synchronized (mPidsSelfLocked) {
                this.mPidsSelfLocked.put(startResult.pid, app);
                if (isActivityProcess) {
                    Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                    msg.obj = app;
                    mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                            ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
                }
            }			

最后会调用Process.start方法启动一个进程,启动进程后,会发送一个PROC_START_TIMEOUT_MSG消息,这个消息用来防止进程启动超时。如果超时弹出ANR对话框。

2.4 调整进程中的位置

AMS中代码经常调用updateLruProcessLocked来调整进程在mLruProcess列表的位置。在这个列表中,最近活动过得进程总是位于最高位置,同时拥有Activity的进程位置总是高于只有Service的进程位置。

2.5 调整进程的oom_adj值

AMS中调整oom_adj值的函数是updateOomAdjLocked,下面选了一段代码:

for (int i=N-1; i>=0; i--) {//从后面遍历mLruProcesses列表
            ProcessRecord app = mLruProcesses.get(i);
            if (!app.killedByAm && app.thread != null) {
                app.procStateChanged = false;
                computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);

                // If we haven't yet assigned the final cached adj
                // to the process, do that now.
                if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
                    switch (app.curProcState) {
                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
                            // This process is a cached process holding activities...
                            // assign it the next cached value for that type, and then
                            // step that cached level.
                            app.curRawAdj = curCachedAdj;
                            app.curAdj = app.modifyRawOomAdj(curCachedAdj);
                            if (DEBUG_LRU && false) Slog.d(TAG, "Assigning activity LRU #" + i
                                    + " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj
                                    + ")");
                            if (curCachedAdj != nextCachedAdj) {
                                stepCached++;
                                if (stepCached >= cachedFactor) {
                                    stepCached = 0;
                                    curCachedAdj = nextCachedAdj;
                                    nextCachedAdj += 2;//mLruProcesses列表越前面adj的值越大
                                    if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
                                        nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
                                    }
                                }
                            }
                            break;

从上面的代码看出mLruProcesses列表越前面adj的值越大,也就越有可能被kill掉。



    原文作者:kc专栏
    原文地址: https://blog.csdn.net/kc58236582/article/details/50065925
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞