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可是在任何地方使用

 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将会出现在用户面前。

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