Android 4.4 AMS 学习笔记

对比着4.4 和书上讲的4.0源码,大概看了看,源码中变化还是很大的。

【插一句,其实所谓的AMS,PKMS,以及WMS等都是运行在system_server这个进程中的线程】

首先看main函数,大体内容都一样,

重要的数据结构:
1. AThread thr =new AThread(); //这个AThread来完成AMS的部分初始化工作。

AThread线程跟main函数相互等待确认。

题外话:顺便说下wait跟sleep函数的区别:

1. 来自不同的类

   sleep是Thread类的静态方法,谁调用谁去睡觉。sleep是占用cpu去睡觉,而wait是放弃cpu去睡觉

2. sleep没有释放锁,而wait释放了锁,sleep不会让出cpu资源,wait是进入线程池等待,一般wait是不会使用时间参数,他必须等待别人notify他才会进入就绪队中。而sleep只要时间到了,就会自动进入就绪队列。如果等不及了,只能通过interrupt来强项打断。

3. wait,notify以及notifyall只能在同步控制方法或者同步控制块中使用,而sleep可是在任何地方使用

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. synchronized(x){  
  2.      x.notify()  
  3.     //或者wait()  
  4.   }  

4. sleep必须捕获异常,而其他3个则不需要

AThread这个线程跟4.0差不多,没太大区别。

回到AMS的构造函数。

这个貌似多了些东西:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. mFgBroadcastQueue = new BroadcastQueue(this“foreground”, BROADCAST_FG_TIMEOUT, false);  
  2.         mBgBroadcastQueue = new BroadcastQueue(this“background”, BROADCAST_BG_TIMEOUT, true);  
  3.         mBroadcastQueues[0] = mFgBroadcastQueue;  
  4.         mBroadcastQueues[1] = mBgBroadcastQueue;  
  5.   
  6.         mServices = new ActiveServices(this);  
  7.         mProviderMap = new ProviderMap(this);  

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. final ActiveServices mServices;  
  2. inal ProviderMap mProviderMap;  

不知道这4个变量是干嘛用的,看名字,前2个是广播消息队列,后两个嘛,暂时还不知道???连个注释都没给

然后创建system目录,创建BBS和USS

创建USS之前,多了一个:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1.  /** 
  2.      * Tracking long-term execution of processes to look for abuse and other 
  3.      * bad app behavior. 
  4.      */  
  5. final ProcessStatsService mProcessStats;  
  6. mProcessStats = new ProcessStatsService(thisnew File(systemDir, “procstats”));  

根据注释,是一个进程来统计不用的app以及不好行为的app的信息

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. /** 
  2.      * Information about and control over application operations 
  3.      */  
  4.     final AppOpsService mAppOpsService;  
  5.  mAppOpsService = new AppOpsService(new File(systemDir, “appops.xml”));  
  6.   
  7.  /** 
  8.      * File storing persisted {@link #mGrantedUriPermissions}. 
  9.      */  
  10.     private final AtomicFile mGrantFile;  
  11.  mGrantFile = new AtomicFile(new File(systemDir, “urigrants.xml”));  
  12.   
  13.   mHeadless = “1”.equals(SystemProperties.get(“ro.config.headless”“0”));  
  14.   
  15.         // User 0 is the first and only user that runs at boot.  
  16.         mStartedUsers.put(0new UserStartedState(new UserHandle(0), true));  
  17.         mUserLru.add(Integer.valueOf(0));  
  18.         updateStartedUserArrayLocked();  

多了这么多变量,其中AppOpsService根据注释应该是用来记录PP的控制行为信息的。

mGrantFile。。。不甚懂。

不过mHeadless这个bool变量,只在attachApplication,handleAppCrashLocked,updateConfigurationLocked和startHomeActivityLocked这4个函数用做一些判断使用,没有注释啊。。。看起来跟系统配置相关。

不过4.4中对信息的统计可以大费周章,原来的4.0中使用的是mPrecessStats.init()来读取/proc/stat文件内容,统计kernel以及system运行时信息,可以看到在4.4的时候,统计信息变成了mProcessCpuTracker.init(),用来收集当显示未响应对话框是的进程状态,由mProcessCpuThread线程守护。

然后添加Watchdog监控。启动mProcessCpuThread线程。这个线程的主要工作就是计时统计。

【一句话,就是把mProcessStatsThread换成了mProcessCpuThread】

2. AMS:ActivityThread中的systemMain

跟4.0中的一模一样。

其中attach函数的参数用来描述是否为系统进程。

在attach函数中遇到了大名鼎鼎的Instrumentation类,做项目是的时候,修改了启动activity的流程,在中间的某些步骤直接返回一个错误的值,导致在home界面上无法启动activity,当时的调试跟踪结果为,这个错误的值由Instrumenttation对象接受并抛出异常,我测试的时候发现是抛出的一个securityException,但是不知道为什么luncher的设计者处理该异常的方法是仅仅是弹出一个toast,内容为app not install。

根据文档中的解释,Instrumenttation类的功能是:他是一个工具类,当被启用时,系统先创建它,再通过它来创建其他组件。另外组件跟系统间的交互也通过这个类来传递,这样他就能检测系统和这些组件的交互情况了。

这个函数执行完之后,得到了:
1 一个ActivityThread对象,他代表应用进程的主线程。

2 一个Context对象,他只想的Application环境与framework-res.apk有关。

其目的就是为了system_server进程搭建一个和应用进程一样的Android运行环境。

3.AMS调用ActivityThread.getSystemContext,得到一个context对象

总之,AMS的main函数的主要目的是:1 创建按AMS对象,2.创建Android运行时环境,这个运行时环境包含2个成员变量ActivityThread和ContextImpl。

第一步完成之后,system_server会接着调用AMS的setSystemProcess函数,目的是system_server进程可以加入到AMS中。

来看下这个函数,

4. AMS的setSystemProcess函数:


[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. public static void setSystemProcess() {  
  2.       try {  
  3.           ActivityManagerService m = mSelf;  
  4.   
  5.           ServiceManager.addService(Context.ACTIVITY_SERVICE, m, true);  
  6.           ServiceManager.addService(ProcessStats.SERVICE_NAME, m.mProcessStats);  
  7.           ServiceManager.addService(“meminfo”new MemBinder(m));  
  8.           ServiceManager.addService(“gfxinfo”new GraphicsBinder(m));  
  9.           ServiceManager.addService(“dbinfo”new DbBinder(m));  
  10.           if (MONITOR_CPU_USAGE) {  
  11.               ServiceManager.addService(“cpuinfo”new CpuBinder(m));  
  12.           }  
  13.           ServiceManager.addService(“permission”new PermissionController(m));  
  14.   
  15.           ApplicationInfo info =  
  16.               mSelf.mContext.getPackageManager().getApplicationInfo(  
  17.                           “android”, STOCK_PM_FLAGS);  
  18.           mSystemThread.installSystemApplicationInfo(info);  
  19.   
  20.           synchronized (mSelf) {  
  21.               ProcessRecord app = mSelf.newProcessRecordLocked(info,  
  22.                       info.processName, false);  
  23.               app.persistent = true;  
  24.               app.pid = MY_PID;  
  25.               app.maxAdj = ProcessList.SYSTEM_ADJ;  
  26.               app.makeActive(mSystemThread.getApplicationThread(), mSelf.mProcessStats);  
  27.               mSelf.mProcessNames.put(app.processName, app.uid, app);  
  28.               synchronized (mSelf.mPidsSelfLocked) {  
  29.                   mSelf.mPidsSelfLocked.put(app.pid, app);  
  30.               }  
  31.               mSelf.updateLruProcessLocked(app, truefalse);  
  32.           }  
  33.       } catch (PackageManager.NameNotFoundException e) {  
  34.           throw new RuntimeException(  
  35.                   “Unable to find android system package”, e);  
  36.       }  
  37.   }  

首先向SystemManager注册几个服务:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. ServiceManager.addService(Context.ACTIVITY_SERVICE, m, true);  
  2. ServiceManager.addService(ProcessStats.SERVICE_NAME, m.mProcessStats);  
  3. ServiceManager.addService(“meminfo”new MemBinder(m));  
  4. ServiceManager.addService(“gfxinfo”new GraphicsBinder(m));  
  5. ServiceManager.addService(“dbinfo”new DbBinder(m));  
  6. if (MONITOR_CPU_USAGE) {  
  7.     ServiceManager.addService(“cpuinfo”new CpuBinder(m));  
  8. }  
  9. ServiceManager.addService(“permission”new PermissionController(m));  

比4.0多了一个dbinfo,数据库相关的服务。

然后通过调用函数向PKMS查询名称为android的Application,但是这里边AMS和PKMS之间的交互是通过context来完成的。根据书中的解释,是为了从设计上以及后期扩展性上来这么做的。

再然后就是:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. mSystemThread.installSystemApplicationInfo(info);  

这里的mSystemThread就是ActivityThread。

在这个函数中:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. public void installSystemApplicationInfo(ApplicationInfo info) {  
  2.     synchronized (this) {  
  3.         ContextImpl context = getSystemContext();  
  4.         context.init(new LoadedApk(this“android”, context, info,  
  5.                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), nullthis);  
  6.   
  7.         // give ourselves a default profiler  
  8.         mProfiler = new Profiler();  
  9.     }  
  10. }  

这里主要是context.init这个代码,因为在AMS的main函数中,已经使用了ActivityThread的getSystemContext函数了,这是个单例模式:

创建一个contextImpl对象,这里边使用了context.init函数,不过这里因为new LoadedApk时,第4个参数为null,也就是没有完全建立好Android的上下文环境,而在installSystemApplicationInfo这个函数中,new LoadedApk的第四个参数为ApplicationInfo的一个对象。对应的构造函数如下:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. public LoadedApk(ActivityThread activityThread, String name,  
  2.          Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) {  
  3.      mActivityThread = activityThread;  
  4.      mApplicationInfo = info != null ? info : new ApplicationInfo();  
  5.      mApplicationInfo.packageName = name;  
  6.      mPackageName = name;  
  7.      mAppDir = null;  
  8.      mResDir = null;  
  9.      mSharedLibraries = null;  
  10.      mDataDir = null;  
  11.      mDataDirFile = null;  
  12.      mLibDir = null;  
  13.      mBaseClassLoader = null;  
  14.      mSecurityViolation = false;  
  15.      mIncludeCode = true;  
  16.      mClassLoader = systemContext.getClassLoader();  
  17.      mResources = systemContext.getResources();  
  18.      mDisplayAdjustments.setCompatibilityInfo(compatInfo);  
  19.  }  

要注意一下,AMS只是一个线程,但是它需要跟其他进程中的activity通信(例如启动其他位于另外一个进程中的activity)。因此必须要跨进程通信。很明显需要通过Binder来进行通信。

这里需要说一下:

ApplicationThreadNative类继承与Binder,UML图如下所示:

可以看到接口IApplicationThread定义了AMS和应用进行通信的交互函数,因此IApplicationThread的Binder服务端在应用进程中,因为AMS还需要监听应用进程的死亡通知。可以看下图中关于接口的说明,如果AMS想要停止一个Activity,那么就会调用应用进程IApplicationThread Binder客户端的scheduleStopActivity函数,该函数服务端实现的就是想ActivityThread所在线程发送一个消息。在应用进程中,ActivityThread运行在主线程中,所以这个消息最终在主线程中被处理。

回到AMS的setSystemProcess这个函数中。

插一句,installsystemapplicationinfo这个函数载入framework-res.apk文件,这个文件也需要一个正确的android运行环境,因此context.init才会被初始化2次。

往下走:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. ProcessRecord app = mSelf.newProcessRecordLocked(info,info.processName, false);  

看名字貌似是建立一个新的进程,因为ProcessRecord就是描述一个进程的。

4.4中的代码如下:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,  
  2.             boolean isolated) {  
  3.         String proc = customProcess != null ? customProcess : info.processName;  
  4.         BatteryStatsImpl.Uid.Proc ps = null;  
  5.         BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();  
  6.         int uid = info.uid;  
  7.        <span style=“color:#cc0000;”if (isolated) {  
  8.             int userId = UserHandle.getUserId(uid);  
  9.             int stepsLeft = Process.LAST_ISOLATED_UID – Process.FIRST_ISOLATED_UID + 1;  
  10.             while (true) {  
  11.                 if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID  
  12.                         || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {  
  13.                     mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;  
  14.                 }  
  15.                 uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);  
  16.                 mNextIsolatedProcessUid++;  
  17.                 if (mIsolatedProcesses.indexOfKey(uid) < 0) {  
  18.                     // No process for this uid, use it.  
  19.                     break;  
  20.                 }  
  21.                 stepsLeft–;  
  22.                 if (stepsLeft <= 0) {  
  23.                     return null;  
  24.                 }  
  25.             }  
  26.         }</span>  
  27.         synchronized (stats) {  
  28.             ps = stats.getProcessStatsLocked(info.uid, proc);  
  29.         }  
  30.         return new ProcessRecord(ps, info, proc, uid);  
  31.     }  

其中红色代码是4.0没有的,根据注释。Process.LAST_ISOLATED_UID:99999,是一个完全隔离的沙盒进程中所使用的最后一个进程号,中间红色的代码意思就是给分配一个可用的进程号  。

看看ProcessRecord的构造函数,其中有一个变量叫做 pkgList,在4.4版本中类型变为了:ArrayMap,我去对java不怎么了解,反正他的目的就是因为一个进程中可以运行多个package。代码如下:是String ProcessState键值对,其中ProcessState是ProcessStats的内部类。

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. final ArrayMap<String, ProcessStats.ProcessState> pkgList  

在网上大概找了找,
这种所谓的ArrayMap:ArrayMap 由一个ArrayList后推得到的Map。对反复的顺序提供了精确的控制。面向非常小的Map设计,特别是那些需要经常创建和删除的。对于非常小的Map,创建和反复所付出的代价要比HashMap低得多。但在Map变大以后,性能也会相应地大幅度降低。

应该是种优化吧。

这个函数返回APP之后,在setSystemProcess函数中,给它的一些成员变量赋特殊值,这样针对system_server的ProcessRecord就创建完毕了。

AMS中还有一个成员变量mProcessNames,原型是:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();  

返回去看看这个所谓的ProcessMap,内部在4.4版本中使用的是ArrayMap这种数据结构,而在4.0的版本中使用的是hashmap。看来在Android中大量使用了ArrayMap这种数据结构。也是优化的一个方面。

函数setSystemProcess总结:

1.注册一些服务

2.根据PKMS返回的applicationinfo初始化Android运行环境,并创建一个代表system_server进程的ProcessRecord。也就是AMS可以管理system_server【插一句,话说用一个线程管理进程,这个有点。。。】

5. 现在回到system_server中去,到了installSystemProviders函数中了:

这个主要是加载setting数据库。

也就是将SettingsProvider,apk加载到system_server中去。

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. public static final void installSystemProviders() {  
  2.     List<ProviderInfo> providers;  
  3.     synchronized (mSelf) {  
  4.         ProcessRecord app = mSelf.mProcessNames.get(“system”, Process.SYSTEM_UID);  
  5.         providers = mSelf.generateApplicationProvidersLocked(app);  
  6.         if (providers != null) {  
  7.             for (int i=providers.size()-1; i>=0; i–) {  
  8.                 ProviderInfo pi = (ProviderInfo)providers.get(i);  
  9.                 if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {  
  10.                     Slog.w(TAG, “Not installing system proc provider “ + pi.name  
  11.                             + “: not system .apk”);  
  12.                     providers.remove(i);  
  13.                 }  
  14.             }  
  15.         }  
  16.     }  
  17.     if (providers != null) {  
  18.         mSystemThread.installSystemProviders(providers);  
  19.     }  
  20.   
  21.     mSelf.mCoreSettingsObserver = new CoreSettingsObserver(mSelf);  
  22.   
  23.     mSelf.mUsageStatsService.monitorPackages();  
  24. }  

首先拿回之前在installSystemApplication中创建的那个ProcessRecord,它代表System_server进程。

然后看那个关键的调用:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. providers = mSelf.generateApplicationProvidersLocked(app);  

这个函数中第一步是想PKMS查询满足要求的ProviderInfo,然后将他们分别保存的AMS和ProcessRecord中的对应的数据结构中。

AMS保存ContentProvider的原因是他要管理ContentProvider,

ProcessRecord保存的原因是COntentProvider最终会落实到一个进程中,其实也是为了方便AMS管理,如果进程一旦推退出,AMS需要把其中的ContentProvider信息从系统中除去。
得到Provider信息之后,下一步工作就是调用ActivityThread的installSystemProvider函数来创建ContentProvider实例,即SettingProvider对象。

这个函数内部的调用InstallContentProvider函数(是所有ContentProvider产生的必经之路)

这个函数的代码如下:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. private void installContentProviders(  
  2.            Context context, List<ProviderInfo> providers) {  
  3.        final ArrayList<IActivityManager.ContentProviderHolder> results =  
  4.            new ArrayList<IActivityManager.ContentProviderHolder>();  
  5.   
  6.        for (ProviderInfo cpi : providers) {  
  7.            if (DEBUG_PROVIDER) {  
  8.                StringBuilder buf = new StringBuilder(128);  
  9.                buf.append(“Pub “);  
  10.                buf.append(cpi.authority);  
  11.                buf.append(“: “);  
  12.                buf.append(cpi.name);  
  13.                Log.i(TAG, buf.toString());  
  14.            }  
  15.            IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,  
  16.                    false /*noisy*/true /*noReleaseNeeded*/true /*stable*/);  
  17.            if (cph != null) {  
  18.                cph.noReleaseNeeded = true;  
  19.                results.add(cph);  
  20.            }  
  21.        }  
  22.   
  23.        try {  
  24.            ActivityManagerNative.getDefault().publishContentProviders(  
  25.                getApplicationThread(), results);  
  26.        } catch (RemoteException ex) {  
  27.        }  
  28.    }  

在4.0中使用的搜索是Iterator,在4.4中改为了for,功能上应该都差不多。都是通过installProvider函数来火得一个IContentProvider对象。然后向AMS发布这个ContentProvider实例,这样之后,一个APK中声明的ContentProvider才能发挥其该有的作用。

【先创建+后注册】

ActivityThread中的intallProvider函数在后半部分跟4.0变化特别大,不过暂时我还看不大懂是什么,暂且先放下吧。

然后就是发布,工作流程跟4.0一样:但是存储的数据结构变了。

现根据调用者的PID找到对应的ProcessRecord,该ProcessRecord的pubProvider中保存了ContentProviderRecord信息,该信息由前面的AMS的generateApplicationProvidersLocked函数根据Package本身的信息生成,如果判断返回成功,则将改ContentProvider以及对应的authority加入到mProviderMap中

在4.0中使用的是mProvidersByClass,4.4中使用的是mProviderMap,他的原型是就是一个ProviderMap,里边把4.0中使用的Map全部扔到一个类中。应该也是方便管理吧,再者根据这些变动的代码,可以明显的看出Android以后一定会是一个多用户的系统,这个类中也添加了关于User的东西。

mLaunchingProviders和最后的notifyAll函数用于通知那些等待ContentProvider所在进程启动的客户端进程。

例如: 进程A要查询一个数据库,需要通过进程B中的某个ContentProvider来实施,如果B还没有启动,那么AMS需要先启动B,这段时间内,A需要等待B启动并注册对应的ContentProvider,一旦B注册完成,就需要告知A退出等待以继续后续的查询工作。

现在一个SettingProvider就算是在系统中正式挂牌并注册了。

这个InstallSystemProvider函数其实就是用于启动SettingProvider。

6. 最后是systemReady

同样的,在4.0中的第一阶段的工作上,作为最后一个广播的接收者注册一个回调通知,当他处理完广播之后,会调用该回调,而在4.4中的对象变为了最后一个用户的最后一个广播接收者。其他的也太无变化。

第二阶段:杀死那些在AMS还未启动完毕就先启动的应用进程,然后从Settings数据库获取配置信息。

第三节阶段:调用SystemReady设置的回调对象goingCallback的run函数,启动那些声明了persistent的APK,启动桌面。

goingCallback函数会启动SystemUI,调用其他服务的systemReady,启动watchDog。

SystemUIService由SystemUi.apk提供,实现了系统状态栏。

通过resumeTopActivityLocked函数启动Home界面,也就是所谓的Launcher。

最后发送ACTION_BOOT_COMPLETED广播。当HomeAcitvity启动后,ActivityStack的activityIdleInternal被调用,在最后的代码中会调用mService.finishBooting函数。

至此AMS就启动完毕了:

首先AMS的Main函数,穿件AMS实例,建立Android运行环境,得到一个ActivityThread和一个Context对象,

然后调用AMS的setSystemProcess函数,该函数注册AMS和meminfo服务等到ServiceManager中,另外,为system_server创建一个ProcessRecord对象。此时,system_server也被AMS所管理。

再然后调用AMS的installSystemProvider函数,为system_server加载SettingProvider 。

最后调用AMS的systemReady函数,做系统启动完毕前最后一些扫尾工作,该函数调用完毕后,Home将会出现在用户面前。

数据结构

最近看4,4的源码,跟网上讲的ams变的太多了,那个什么mMainStack,还有什么mHistoryRecord等根本找不到,看的一头雾水,先总结下基本的数据结构吧。

其实说白了,他所谓的stack全部都是ArrayList,用ArrayList来模拟stack,开始还很纳闷既然是stack怎么去里边找activity,不是操作栈顶元素么?

全局一个总的stack:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. /** All the non-launcher stacks */  
  2.    private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();  

这个mStacks存储了所有的stack,其中每一个stack中存储是一个个的task,每一个task中存储的是一堆activity。

总体的大小关系是:

mStacks>Stack>task【开始没搞清楚大小关系,纠结了半天,从这个代码就可以看出】

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. void removeTask(TaskRecord task) {  
  2.       mWindowManager.removeTask(task.taskId);  
  3.       final ActivityStack stack = task.stack;  
  4.       final ActivityRecord r = stack.mResumedActivity;  
  5.       if (r != null && r.task == task) {  
  6.           stack.mResumedActivity = null;  
  7.       }  
  8.       if (stack.removeTask(task) && !stack.isHomeStack()) {  
  9.           if (DEBUG_STACK) Slog.i(TAG, “removeTask: removing stack “ + stack);  
  10.           mStacks.remove(stack);  
  11.           final int stackId = stack.mStackId;  
  12.           final int nextStackId = mWindowManager.removeStack(stackId);  
  13.           // TODO: Perhaps we need to let the ActivityManager determine the next focus…  
  14.           if (mFocusedStack == null || mFocusedStack.mStackId == stackId) {  
  15.               // If this is the last app stack, set mFocusedStack to null.  
  16.               mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId);  
  17.           }  
  18.       }  
  19.   }  

这里删除是个task,首先拿到这个task所在的stack,就是第3行代码,然后删除掉这个stack中的task,
然后注意这行代码:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. mStacks.remove(stack);  

为毛我只删除个task,你就要把我的stack也删掉?难不成task>stack??

关键点在这:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. if (stack.removeTask(task) && !stack.isHomeStack()) {  

这个if语句,我们回到stack中去看看他的removeTask的实现:

[javascript] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. boolean removeTask(TaskRecord task) {  
  2.       final int taskNdx = mTaskHistory.indexOf(task);  
  3.       final int topTaskNdx = mTaskHistory.size() – 1;  
  4.       if (task.mOnTopOfHome && taskNdx < topTaskNdx) {  
  5.           mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;  
  6.       }  
  7.       mTaskHistory.remove(task);  
  8.       return mTaskHistory.isEmpty();  
  9.   }  

原来在stack中删除task的时候,最后会做出个判断,看当前stack中的task是否为空,
如果为没东西了,那么这个stack也就可以删除了。

这也就证明了mStacks>stack>task

遍观整个ActivityStackSupervisor.java会发现其实关于stack除了mStacks是整个stack的集合,一共也就2个stack,分别是:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. /** The stack containing the launcher app */  
  2.   private ActivityStack mHomeStack;  
  3.   
  4.   /** The non-home stack currently receiving input or launching the next activity. If home is 
  5.    * in front then mHomeStack overrides mFocusedStack. 
  6.    * DO NOT ACCESS DIRECTLY – It may be null, use getFocusedStack() */  
  7.   private ActivityStack mFocusedStack;  

就这2个东西,
mHomeStack存储luncher相关的内容,也就是home,另一个存储当前处于焦点的stack,mHomeStack会在开机之后自动加入到mStacks中去,而且只占据第0号位置,mFocusedStack占据第1号位置,

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. void setWindowManager(WindowManagerService wm) {  
  2.     mWindowManager = wm;  
  3.     mHomeStack = new ActivityStack(mService, mContext, mLooper, HOME_STACK_ID);//初始化home  
  4.     mStacks.add(mHomeStack);  
  5. }  

调试的时候开启了10多个应用,发现这些应用的activity全部放到了mFocusedStack中,mStacks中第2个位置始终没有被使用很纳闷,不知道是不是我应用开的不够多,如果仅仅用2个位置的话,那么要mStacks岂不是多此一举?这个还得好好琢磨琢磨。

看这个:

[java] 
view plain
copy
《Android 4.4 AMS 学习笔记》
《Android 4.4 AMS 学习笔记》

  1. ActivityStack getLastStack() {  
  2.      switch (mStackState) {  
  3.          case STACK_STATE_HOME_IN_FRONT:  
  4.          case STACK_STATE_HOME_TO_BACK:  
  5.              return mHomeStack;  
  6.          case STACK_STATE_HOME_TO_FRONT:  
  7.          case STACK_STATE_HOME_IN_BACK:  
  8.          default:  
  9.              return mFocusedStack;  
  10.      }  
  11.  }  

貌似就是在这两个stack中来回切换,关于是否会使用第3个位置,还有需要进一步确认。

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