本文共 16170 字,大约阅读时间需要 53 分钟。
对比着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可是在任何地方使用
- synchronized(x){
- x.notify()
-
- }
4. sleep必须捕获异常,而其他3个则不需要
AThread这个线程跟4.0差不多,没太大区别。
回到AMS的构造函数。
这个貌似多了些东西:
- mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT, false);
- mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT, true);
- mBroadcastQueues[0] = mFgBroadcastQueue;
- mBroadcastQueues[1] = mBgBroadcastQueue;
-
- mServices = new ActiveServices(this);
- mProviderMap = new ProviderMap(this);
- final ActiveServices mServices;
- inal ProviderMap mProviderMap;
不知道这4个变量是干嘛用的,看名字,前2个是广播消息队列,后两个嘛,暂时还不知道???连个注释都没给
然后创建system目录,创建BBS和USS
创建USS之前,多了一个:
-
-
-
-
- final ProcessStatsService mProcessStats;
- mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
根据注释,是一个进程来统计不用的app以及不好行为的app的信息
-
-
-
- final AppOpsService mAppOpsService;
- mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"));
-
-
-
-
- private final AtomicFile mGrantFile;
- mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
-
- mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
-
-
- mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
- mUserLru.add(Integer.valueOf(0));
- 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函数:
- public static void setSystemProcess() {
- try {
- ActivityManagerService m = mSelf;
-
- ServiceManager.addService(Context.ACTIVITY_SERVICE, m, true);
- ServiceManager.addService(ProcessStats.SERVICE_NAME, m.mProcessStats);
- ServiceManager.addService("meminfo", new MemBinder(m));
- ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
- ServiceManager.addService("dbinfo", new DbBinder(m));
- if (MONITOR_CPU_USAGE) {
- ServiceManager.addService("cpuinfo", new CpuBinder(m));
- }
- ServiceManager.addService("permission", new PermissionController(m));
-
- ApplicationInfo info =
- mSelf.mContext.getPackageManager().getApplicationInfo(
- "android", STOCK_PM_FLAGS);
- mSystemThread.installSystemApplicationInfo(info);
-
- synchronized (mSelf) {
- ProcessRecord app = mSelf.newProcessRecordLocked(info,
- info.processName, false);
- app.persistent = true;
- app.pid = MY_PID;
- app.maxAdj = ProcessList.SYSTEM_ADJ;
- app.makeActive(mSystemThread.getApplicationThread(), mSelf.mProcessStats);
- mSelf.mProcessNames.put(app.processName, app.uid, app);
- synchronized (mSelf.mPidsSelfLocked) {
- mSelf.mPidsSelfLocked.put(app.pid, app);
- }
- mSelf.updateLruProcessLocked(app, true, false);
- }
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(
- "Unable to find android system package", e);
- }
- }
首先向SystemManager注册几个服务:
- ServiceManager.addService(Context.ACTIVITY_SERVICE, m, true);
- ServiceManager.addService(ProcessStats.SERVICE_NAME, m.mProcessStats);
- ServiceManager.addService("meminfo", new MemBinder(m));
- ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
- ServiceManager.addService("dbinfo", new DbBinder(m));
- if (MONITOR_CPU_USAGE) {
- ServiceManager.addService("cpuinfo", new CpuBinder(m));
- }
- ServiceManager.addService("permission", new PermissionController(m));
比4.0多了一个dbinfo,数据库相关的服务。
然后通过调用函数向PKMS查询名称为android的Application,但是这里边AMS和PKMS之间的交互是通过context来完成的。根据书中的解释,是为了从设计上以及后期扩展性上来这么做的。
再然后就是:
- mSystemThread.installSystemApplicationInfo(info);
这里的mSystemThread就是ActivityThread。
在这个函数中:
- public void installSystemApplicationInfo(ApplicationInfo info) {
- synchronized (this) {
- ContextImpl context = getSystemContext();
- context.init(new LoadedApk(this, "android", context, info,
- CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), null, this);
-
-
- mProfiler = new Profiler();
- }
- }
这里主要是context.init这个代码,因为在AMS的main函数中,已经使用了ActivityThread的getSystemContext函数了,这是个单例模式:
创建一个contextImpl对象,这里边使用了context.init函数,不过这里因为new LoadedApk时,第4个参数为null,也就是没有完全建立好Android的上下文环境,而在installSystemApplicationInfo这个函数中,new LoadedApk的第四个参数为ApplicationInfo的一个对象。对应的构造函数如下:
- public LoadedApk(ActivityThread activityThread, String name,
- Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) {
- mActivityThread = activityThread;
- mApplicationInfo = info != null ? info : new ApplicationInfo();
- mApplicationInfo.packageName = name;
- mPackageName = name;
- mAppDir = null;
- mResDir = null;
- mSharedLibraries = null;
- mDataDir = null;
- mDataDirFile = null;
- mLibDir = null;
- mBaseClassLoader = null;
- mSecurityViolation = false;
- mIncludeCode = true;
- mClassLoader = systemContext.getClassLoader();
- mResources = systemContext.getResources();
- mDisplayAdjustments.setCompatibilityInfo(compatInfo);
- }
要注意一下,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次。
往下走:
- ProcessRecord app = mSelf.newProcessRecordLocked(info,info.processName, false);
看名字貌似是建立一个新的进程,因为ProcessRecord就是描述一个进程的。
4.4中的代码如下:
- final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
- boolean isolated) {
- String proc = customProcess != null ? customProcess : info.processName;
- BatteryStatsImpl.Uid.Proc ps = null;
- BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- int uid = info.uid;
- <span style="color:#cc0000;"> if (isolated) {
- int userId = UserHandle.getUserId(uid);
- int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
- while (true) {
- if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID
- || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
- mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;
- }
- uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
- mNextIsolatedProcessUid++;
- if (mIsolatedProcesses.indexOfKey(uid) < 0) {
-
- break;
- }
- stepsLeft--;
- if (stepsLeft <= 0) {
- return null;
- }
- }
- }</span>
- synchronized (stats) {
- ps = stats.getProcessStatsLocked(info.uid, proc);
- }
- return new ProcessRecord(ps, info, proc, uid);
- }
其中红色代码是4.0没有的,根据注释。Process.LAST_ISOLATED_UID:99999,是一个完全隔离的沙盒进程中所使用的最后一个进程号,中间红色的代码意思就是给分配一个可用的进程号 。
看看ProcessRecord的构造函数,其中有一个变量叫做 pkgList,在4.4版本中类型变为了:ArrayMap,我去对java不怎么了解,反正他的目的就是因为一个进程中可以运行多个package。代码如下:是String ProcessState键值对,其中ProcessState是ProcessStats的内部类。
- final ArrayMap<String, ProcessStats.ProcessState> pkgList
在网上大概找了找, 这种所谓的ArrayMap:ArrayMap 由一个ArrayList后推得到的Map。对反复的顺序提供了精确的控制。面向非常小的Map设计,特别是那些需要经常创建和删除的。对于非常小的Map,创建和反复所付出的代价要比HashMap低得多。但在Map变大以后,性能也会相应地大幅度降低。
应该是种优化吧。
这个函数返回APP之后,在setSystemProcess函数中,给它的一些成员变量赋特殊值,这样针对system_server的ProcessRecord就创建完毕了。
AMS中还有一个成员变量mProcessNames,原型是:
- 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中去。
- public static final void installSystemProviders() {
- List<ProviderInfo> providers;
- synchronized (mSelf) {
- ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
- providers = mSelf.generateApplicationProvidersLocked(app);
- 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);
- }
-
- mSelf.mCoreSettingsObserver = new CoreSettingsObserver(mSelf);
-
- mSelf.mUsageStatsService.monitorPackages();
- }
首先拿回之前在installSystemApplication中创建的那个ProcessRecord,它代表System_server进程。
然后看那个关键的调用:
- providers = mSelf.generateApplicationProvidersLocked(app);
这个函数中第一步是想PKMS查询满足要求的ProviderInfo,然后将他们分别保存的AMS和ProcessRecord中的对应的数据结构中。
AMS保存ContentProvider的原因是他要管理ContentProvider,
ProcessRecord保存的原因是COntentProvider最终会落实到一个进程中,其实也是为了方便AMS管理,如果进程一旦推退出,AMS需要把其中的ContentProvider信息从系统中除去。
得到Provider信息之后,下一步工作就是调用ActivityThread的installSystemProvider函数来创建ContentProvider实例,即SettingProvider对象。
这个函数内部的调用InstallContentProvider函数(是所有ContentProvider产生的必经之路)
这个函数的代码如下:
- private void installContentProviders(
- Context context, List<ProviderInfo> providers) {
- final ArrayList<IActivityManager.ContentProviderHolder> results =
- new ArrayList<IActivityManager.ContentProviderHolder>();
-
- for (ProviderInfo cpi : providers) {
- if (DEBUG_PROVIDER) {
- StringBuilder buf = new StringBuilder(128);
- buf.append("Pub ");
- buf.append(cpi.authority);
- buf.append(": ");
- buf.append(cpi.name);
- Log.i(TAG, buf.toString());
- }
- IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
- false , true , true );
- if (cph != null) {
- cph.noReleaseNeeded = true;
- results.add(cph);
- }
- }
-
- try {
- ActivityManagerNative.getDefault().publishContentProviders(
- getApplicationThread(), results);
- } catch (RemoteException ex) {
- }
- }
在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:
-
- private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
这个mStacks存储了所有的stack,其中每一个stack中存储是一个个的task,每一个task中存储的是一堆activity。
总体的大小关系是:
mStacks>Stack>task【开始没搞清楚大小关系,纠结了半天,从这个代码就可以看出】
- void removeTask(TaskRecord task) {
- mWindowManager.removeTask(task.taskId);
- final ActivityStack stack = task.stack;
- final ActivityRecord r = stack.mResumedActivity;
- if (r != null && r.task == task) {
- stack.mResumedActivity = null;
- }
- if (stack.removeTask(task) && !stack.isHomeStack()) {
- if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack " + stack);
- mStacks.remove(stack);
- final int stackId = stack.mStackId;
- final int nextStackId = mWindowManager.removeStack(stackId);
-
- if (mFocusedStack == null || mFocusedStack.mStackId == stackId) {
-
- mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId);
- }
- }
- }
这里删除是个task,首先拿到这个task所在的stack,就是第3行代码,然后删除掉这个stack中的task, 然后注意这行代码:
为毛我只删除个task,你就要把我的stack也删掉?难不成task>stack??
关键点在这:
- if (stack.removeTask(task) && !stack.isHomeStack()) {
这个if语句,我们回到stack中去看看他的removeTask的实现:
- boolean removeTask(TaskRecord task) {
- final int taskNdx = mTaskHistory.indexOf(task);
- final int topTaskNdx = mTaskHistory.size() - 1;
- if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
- mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
- }
- mTaskHistory.remove(task);
- return mTaskHistory.isEmpty();
- }
原来在stack中删除task的时候,最后会做出个判断,看当前stack中的task是否为空, 如果为没东西了,那么这个stack也就可以删除了。
这也就证明了mStacks>stack>task
遍观整个ActivityStackSupervisor.java会发现其实关于stack除了mStacks是整个stack的集合,一共也就2个stack,分别是:
-
- private ActivityStack mHomeStack;
-
-
-
-
- private ActivityStack mFocusedStack;
就这2个东西, mHomeStack存储luncher相关的内容,也就是home,另一个存储当前处于焦点的stack,mHomeStack会在开机之后自动加入到mStacks中去,而且只占据第0号位置,mFocusedStack占据第1号位置,
- void setWindowManager(WindowManagerService wm) {
- mWindowManager = wm;
- mHomeStack = new ActivityStack(mService, mContext, mLooper, HOME_STACK_ID);
- mStacks.add(mHomeStack);
- }
调试的时候开启了10多个应用,发现这些应用的activity全部放到了mFocusedStack中,mStacks中第2个位置始终没有被使用,很纳闷,不知道是不是我应用开的不够多,如果仅仅用2个位置的话,那么要mStacks岂不是多此一举?这个还得好好琢磨琢磨。
看这个:
- ActivityStack getLastStack() {
- switch (mStackState) {
- case STACK_STATE_HOME_IN_FRONT:
- case STACK_STATE_HOME_TO_BACK:
- return mHomeStack;
- case STACK_STATE_HOME_TO_FRONT:
- case STACK_STATE_HOME_IN_BACK:
- default:
- return mFocusedStack;
- }
- }
貌似就是在这两个stack中来回切换,关于是否会使用第3个位置,还有需要进一步确认。 转载地址:http://ftuni.baihongyu.com/