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 gDefault = new Singleton() {        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 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();                    }                    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

这段代码主要启动带有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掉。





更多相关文章

  1. android中的跨进程通信的实现(一)——远程调用过程和aidl
  2. android 程序开发的插件化 模块化方法
  3. 利用Android多进程机制来分割组件
  4. android studio 3.x 以上版本的Native JNI/NDK 调用c++/c语言程
  5. Android WebView 不支持 H5 input type="file" 解决方法
  6. 在Android App开发中实现任意Java方法的拦截
  7. 关于Android长按出现复制粘贴栏在顶部占位问题解决方法
  8. Android进程和应用生命周期
  9. Android进程保活方法 --转自腾讯Bugly公众号

随机推荐

  1. Android(安卓)插件化原理 完胜360插件框
  2. 【30篇突击 android】源码统计 十五
  3. android viewpaper嵌套viewpaper,滑动问题
  4. android6.0 源码 系统应用之Music代码之
  5. android编译时没有规则可以创建“out/tar
  6. android deal with big images
  7. android 外部启动activity,自定义action,ac
  8. Android拍照后图片旋转问题
  9. Android 自定义View 基础知识
  10. Android apk运行时错误java.lang.NoSuchM