Android 4.4 AMS 学习笔记(一)
2014-04-17 11:36
471 查看
对比着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可是在任何地方使用
4. sleep必须捕获异常,而其他3个则不需要
AThread这个线程跟4.0差不多,没太大区别。
回到AMS的构造函数。
这个貌似多了些东西:
不知道这4个变量是干嘛用的,看名字,前2个是广播消息队列,后两个嘛,暂时还不知道???连个注释都没给
然后创建system目录,创建BBS和USS
创建USS之前,多了一个:
多了这么多变量,其中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函数:
首先向SystemManager注册几个服务:
比4.0多了一个dbinfo,数据库相关的服务。
然后通过调用函数向PKMS查询名称为android的Application,但是这里边AMS和PKMS之间的交互是通过context来完成的。根据书中的解释,是为了从设计上以及后期扩展性上来这么做的。
再然后就是:
这里的mSystemThread就是ActivityThread。
在这个函数中:
这里主要是context.init这个代码,因为在AMS的main函数中,已经使用了ActivityThread的getSystemContext函数了,这是个单例模式:
创建一个contextImpl对象,这里边使用了context.init函数,不过这里因为new LoadedApk时,第4个参数为null,也就是没有完全建立好Android的上下文环境,而在installSystemApplicationInfo这个函数中,new LoadedApk的第四个参数为ApplicationInfo的一个对象。对应的构造函数如下:
要注意一下,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次。
往下走:
4.4中的代码如下:
其中红色代码是4.0没有的,根据注释。Process.LAST_ISOLATED_UID:99999,是一个完全隔离的沙盒进程中所使用的最后一个进程号,中间红色的代码意思就是给分配一个可用的进程号 。
看看ProcessRecord的构造函数,其中有一个变量叫做 pkgList,在4.4版本中类型变为了:ArrayMap,我去对java不怎么了解,反正他的目的就是因为一个进程中可以运行多个package。代码如下:是String ProcessState键值对,其中ProcessState是ProcessStats的内部类。
应该是种优化吧。
这个函数返回APP之后,在setSystemProcess函数中,给它的一些成员变量赋特殊值,这样针对system_server的ProcessRecord就创建完毕了。
AMS中还有一个成员变量mProcessNames,原型是:
函数setSystemProcess总结:
1.注册一些服务
2.根据PKMS返回的applicationinfo初始化Android运行环境,并创建一个代表system_server进程的ProcessRecord。也就是AMS可以管理system_server【插一句,话说用一个线程管理进程,这个有点。。。】
5. 现在回到system_server中去,到了installSystemProviders函数中了:
这个主要是加载setting数据库。
也就是将SettingsProvider,apk加载到system_server中去。
首先拿回之前在installSystemApplication中创建的那个ProcessRecord,它代表System_server进程。
然后看那个关键的调用:
AMS保存ContentProvider的原因是他要管理ContentProvider,
ProcessRecord保存的原因是COntentProvider最终会落实到一个进程中,其实也是为了方便AMS管理,如果进程一旦推退出,AMS需要把其中的ContentProvider信息从系统中除去。
得到Provider信息之后,下一步工作就是调用ActivityThread的installSystemProvider函数来创建ContentProvider实例,即SettingProvider对象。
这个函数内部的调用InstallContentProvider函数(是所有ContentProvider产生的必经之路)
这个函数的代码如下:
在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将会出现在用户面前。
【插一句,其实所谓的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() //或者wait() }
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; final ProviderMap mProviderMap;
不知道这4个变量是干嘛用的,看名字,前2个是广播消息队列,后两个嘛,暂时还不知道???连个注释都没给
然后创建system目录,创建BBS和USS
创建USS之前,多了一个:
/** * Tracking long-term execution of processes to look for abuse and other * bad app behavior. */ final ProcessStatsService mProcessStats; mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));根据注释,是一个进程来统计不用的app以及不好行为的app的信息
/** * Information about and control over application operations */ final AppOpsService mAppOpsService; mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml")); /** * File storing persisted {@link #mGrantedUriPermissions}. */ private final AtomicFile mGrantFile; mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml")); mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0")); // User 0 is the first and only user that runs at boot. 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); // give ourselves a default profiler 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; 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) { // No process for this uid, use it. break; } stepsLeft--; if (stepsLeft <= 0) { return null; } } } 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 /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/); 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将会出现在用户面前。
相关文章推荐
- Android 4.4 AMS 学习笔记
- android内核剖析学习笔记:AMS(ActivityManagerService)内部原理和工作机制
- Android开发学习笔记(5):Notification和NotificationManager
- Android开发学习笔记:浅谈WebView
- 学习笔记 android开发 一些函数记录
- Android 学习笔记 二十二 之Handler
- Android 学习笔记5---程序开发模式&拨号器&短信发送器小例程
- Android(java)学习笔记156:Java虚拟机和Dalvik虚拟机的区别
- Android Animation学习笔记
- Android(java)学习笔记157:使用Dexdump等工具进行反编译
- Android开发————Alarm学习笔记
- Android 学习笔记之五 activity lanuch mode
- Android应用开发学习笔记之播放音频
- Android(java)学习笔记160:Framework运行环境之 Android进程产生过程
- Android(4.X)学习笔记
- Android:日常学习笔记(2)——分析第一个Android应用程序
- android游戏开发学习笔记二(学习书籍 Android游戏编程之从零开始)
- Android 4.4 Kitkat Phone工作流程浅析(一)__概要和学习计划
- Android入门学习笔记(二):Android开发环境的搭建
- android开发学习笔记(2)android的基本介绍