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