对比着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()
//或者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将会出现在用户面前。