《深入理解Android2》读书笔记(四)

接上篇《深入理解Android2》读书笔记(三)

ActivityManagerService(AMS)

1.AMS由ActivityManagerNative(AMN)类派生,并实现Watchdog.Monitor和BatteryStatsImpl.BatteryCallback接口。而AMN由Binder派生,实现了IActivityManager接口。

2.客户端使用ActivityManager类。由于AMS是系统核心服务,很多API不能开放供客户端使用,因此设计者没有让ActivityManager直接加入AMS家庭。ActivityManager类内部通过调用AMN的getDefault函数得到一个ActivityManagerProxy对象,通过它可与AMS通信。

public static final Context main(int factoryTest){
    AThread thr = new AThread();//创建一个AThread线程对象
    thr.start();
    ActivityManagerService m = thr.mService;
    mSelf = m;
    //调用ActivityThread的systemMain函数
    ActivityThread at = ActivityThread.systemMain();
    mSystemThread = at;
    
    //得到一个Context对象,注意调用的函数名为getSystemContext,何为System Context
    Context context = at.getSystemContext();
    context.setTheme(android.R.style.Theme_Holo);
    m.mContext = context;
    m.mFactoryTest = factoryTest;
    
    //ActivityStack是AMS中用来管理Activity的启动和调度的核心类,以后再分析它
    m.mMainStack = new ActivityStack(m,context,true);
    //调用BSS的public函数,这个知识点我们在第5章介绍过了
    m.mBatteryStatsService.publish(context);
    //另外一个service:UsageStatsService.读者阅读完本章后自行分析它
    m.mUsageStatsService.publish(context);
    synchronized(thr){
        thr.mReady = true;
        thr.notifyAll();//通知thr线程,本线程工作完成
    }
    
    //调用AMS的startRunning函数
    m.startRunning(null,null,null,null);
    
    return context;
}

其中四个函数分别是

1.创建AThread线程。虽然AMS的main函数由ServerThread线程调用,但是AMS自己的工作并没有放在ServerThread中去做,而是新创建了一个线程,即AThread线程

2.ActivityThread.systemMain函数。初始化ActivityThread对象

3.ActivityThread.getSystemContext函数。用于获取一个Context对象,从函数名上看,该Context代表了System的上下文环境。

4.AMS的startRunning函数。

main函数中有一处等待(wait)、一处通知(notifyAll),因为

1.main函数首先需要等到AThread所在线程启动并完成一部分工作

2.AThread完成那一部分工作后,将等待main函数完成后续的工作

以上函数我在SDK23的版本并没有找到,权当记录了,下面来分析构造函数

public ActivityManagerService(Context systemContext) {
    mContext = systemContext;
    mFactoryTest = FactoryTest.getMode();
    mSystemThread = ActivityThread.currentActivityThread();

    Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());

    mHandlerThread = new ServiceThread(TAG,
            android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
    mHandlerThread.start();
    mHandler = new MainHandler(mHandlerThread.getLooper());
    mUiHandler = new UiHandler();

    mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "foreground", BROADCAST_FG_TIMEOUT, false);
    mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "background", BROADCAST_BG_TIMEOUT, true);
    mBroadcastQueues[0] = mFgBroadcastQueue;
    mBroadcastQueues[1] = mBgBroadcastQueue;

    mServices = new ActiveServices(this);
    mProviderMap = new ProviderMap(this);

    // TODO: Move creation of battery stats service outside of activity manager service.
    File dataDir = Environment.getDataDirectory();
    File systemDir = new File(dataDir, "system");
    systemDir.mkdirs();
    mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
    mBatteryStatsService.getActiveStatistics().readLocked();
    mBatteryStatsService.scheduleWriteToDisk();
    mOnBattery = DEBUG_POWER ? true
            : mBatteryStatsService.getActiveStatistics().getIsOnBattery();
    mBatteryStatsService.getActiveStatistics().setCallback(this);

    mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));

    mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);

    mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));

    // User 0 is the first and only user that runs at boot.
    mStartedUsers.put(UserHandle.USER_OWNER, new UserState(UserHandle.OWNER, true));
    mUserLru.add(UserHandle.USER_OWNER);
    updateStartedUserArrayLocked();

    GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
        ConfigurationInfo.GL_ES_VERSION_UNDEFINED);

    mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));

    mConfiguration.setToDefaults();
    mConfiguration.setLocale(Locale.getDefault());

    mConfigurationSeq = mConfiguration.seq = 1;
    mProcessCpuTracker.init();

    mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
    mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
    mRecentTasks = new RecentTasks(this);
    mStackSupervisor = new ActivityStackSupervisor(this, mRecentTasks);
    mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, mRecentTasks);

    mProcessCpuThread = new Thread("CpuTracker") {
        @Override
        public void run() {
            while (true) {
                try {
                    try {
                        synchronized(this) {
                            final long now = SystemClock.uptimeMillis();
                            long nextCpuDelay = (mLastCpuTime.get()+MONITOR_CPU_MAX_TIME)-now;
                            long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
                            //Slog.i(TAG, "Cpu delay=" + nextCpuDelay
                            //        + ", write delay=" + nextWriteDelay);
                            if (nextWriteDelay < nextCpuDelay) {
                                nextCpuDelay = nextWriteDelay;
                            }
                            if (nextCpuDelay > 0) {
                                mProcessCpuMutexFree.set(true);
                                this.wait(nextCpuDelay);
                            }
                        }
                    } catch (InterruptedException e) {
                    }
                    updateCpuStatsNow();
                } catch (Exception e) {
                    Slog.e(TAG, "Unexpected exception collecting process stats", e);
                }
            }
        }
    };

    Watchdog.getInstance().addMonitor(this);
    Watchdog.getInstance().addThread(mHandler);
}

1.创建BSS、USS、mProcessStats(ProcessStats类型)、mProcessStatsThread线程,这些都与系统运行状况统计相关

2.创建/data/system目录,为mCompatModePackages(CompatModePackages类型)和mConfiguration(Configuration类型)等成员变量赋值

ActivityThread

ActivityThread是Android Framework中一个非常重要的类,它代表一个应用进程的主线程(对于应用进程来说,ActivityThread的main函数确实是由该进程的主线程执行),其职责就是调度及执行在该线程中的四大组件。

应用进程指那些运行APK的进程,它们由Zyote派生(fork)而来,上面运行了dalvik虚拟机。与应用进程相对的就是系统进程(包括Zygote和system_server)。如果apk文件在/data/app目录下,则为应用apk

public static ActivityThread systemMain() {
    // The system process on low-memory devices do not get to use hardware
    // accelerated drawing, since this can add too much overhead to the
    // process.
    if (!ActivityManager.isHighEndGfx()) {
        HardwareRenderer.disable(true);
    } else {
        HardwareRenderer.enableForegroundTrimming();
    }
    ActivityThread thread = new ActivityThread();
    thread.attach(true);
    return thread;
}

通过ActivityThread可以把Android系统提供的组件之间的交互机制和交互接口(如利用Context提供的API)也拓展到system_server中使用。

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                ensureJitEnabled();
            }
        });
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            // Ignore
        }
        // Watch for getting close to heap limit.
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return;
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                            + " total=" + (runtime.totalMemory()/1024)
                            + " used=" + (dalvikUsed/1024));
                    mSomeActivitiesChanged = false;
                    try {
                        mgr.releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                    }
                }
            }
        });
    } else {
        // Don't set application object here -- if the system crashes,
        // we can't display an alert, we just want to die die die.
        android.ddm.DdmHandleAppName.setAppName("system_process",
                UserHandle.myUserId());
        try {
            mInstrumentation = new Instrumentation();
            ContextImpl context = ContextImpl.createAppContext(
                    this, getSystemContext().mPackageInfo);
            mInitialApplication = context.mPackageInfo.makeApplication(true, null);
            mInitialApplication.onCreate();
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to instantiate Application():" + e.toString(), e);
        }
    }

    // add dropbox logging to libcore
    DropBox.setReporter(new DropBoxReporter());

    ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            synchronized (mResourcesManager) {
                // We need to apply this change to the resources
                // immediately, because upon returning the view
                // hierarchy will be informed about it.
                if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
                    // This actually changed the resources!  Tell
                    // everyone about it.
                    if (mPendingConfiguration == null ||
                            mPendingConfiguration.isOtherSeqNewer(newConfig)) {
                        mPendingConfiguration = newConfig;

                        sendMessage(H.CONFIGURATION_CHANGED, newConfig);
                    }
                }
            }
        }
        @Override
        public void onLowMemory() {
        }
        @Override
        public void onTrimMemory(int level) {
        }
    });
}

attach函数中出现几个重要类型Instrumentation类、Application类及Context类,作用如下

1.Instrumentation是一个工具类,当它被启用时,系统先创建它,再通过它来创建其他组件,另外,系统和组件之间的交互也将通过Instrumentation来传递,这样,Instrumentation就能监测系统和这些组件的交互情况了。在实际使用中,我们可以创建Instrumentation的派生类来进行相应的处理。

2.Application类保存了一个全局的application状态。Application由AndroidManifest.xml中的<applicaion>标签声明。在实际使用时需定义Applicaion的派生类(可以理解为一种容器,其内部包含四大组件。一个进程可以运行多个Application)

3.Context是一个接口,通过它可以获取并操作Application对应的资源、类,甚至包含于Application中的四大组件。

public ContextImpl getSystemContext() {
    synchronized (this) {
        if (mSystemContext == null) {
            mSystemContext = ContextImpl.createSystemContext(this);
        }
        return mSystemContext;
    }
}

1.ApplicationContentResolver从ContentResolver派生,它主要用于和ContentProvider打交道。ContextImpl和ContextWrapper均从Context继承,而Application则从ContextWrapper派生

2.ContextImpl涉及的面最广,它通过mResources指向Resources,通过mPackageInfo指向LoadedApk,通过mMainThread指向ActivityThread,通过mContentResolver指向ApplicationContentResolver。

3.ActivityThread代表主线程,它通过mInstrumentation指向Instrumentation。另外,它还保存多个Application对象。

systemMain函数调用结束后,得到了:

1.得到了一个ActivityThread对象,它代表应用进程的主线程

2.得到了一个Context对象,它背后所指向的Application环境与framework-res.apk有关

systemMain函数的目的是为system_server进程搭建一个和应用进程一样的Android运行环境。

1.ContextWrapper是一个代理类,被代理的对象是另外一个Context,其实是ContextImpl,由ContextWrapper通过mBase成员变量指定。ContextWrapper其内部函数功能的实现最终都由mBase完成,这样设计的目的是想把ContextImpl隐藏起来。

2.Application从ContextWrapper派生,并实现了ComponentCallbacks2接口。Application中有一个LoadedApk类型的成员变量mLoadedApk。LoadedApk代表一个APK文件。由于一个AndroidManifest.xml文件只能声明一个Application标签,所以一个Application必然会和一个LoadedApk绑定。

3.Service从ContextWrapper派生,其中Service内部成员变量mApplication指向Application(在AndroidManifest.xml中,Service只能作为Application的子标签,所以在代码中Service必然会和一个Application绑定)。

4.ContextThemeWrapper重载了和Theme(主题)相关的两个函数。这些和界面有关,所以Activity作为Android系统中的UI容器,必然也会从ContextThemeWrapper派生。与Servcie一样,Activity内部也通过mApplication成员变量指向Application。

public void setSystemProcess() {
    try {
        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
        ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
        ServiceManager.addService("meminfo", new MemBinder(this));
        ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
        ServiceManager.addService("dbinfo", new DbBinder(this));
        if (MONITOR_CPU_USAGE) {
            ServiceManager.addService("cpuinfo", new CpuBinder(this));
        }
        ServiceManager.addService("permission", new PermissionController(this));
        ServiceManager.addService("processinfo", new ProcessInfoService(this));

        ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                "android", STOCK_PM_FLAGS);
        mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());

        synchronized (this) {
            ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
            app.persistent = true;
            app.pid = MY_PID;
            app.maxAdj = ProcessList.SYSTEM_ADJ;
            app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.put(app.pid, app);
            }
            updateLruProcessLocked(app, false, null);
            updateOomAdjLocked();
        }
    } catch (PackageManager.NameNotFoundException e) {
        throw new RuntimeException(
                "Unable to find android system package", e);
    }
}

Context第一次执行init的目的仅仅是创建一个Android运行环境,而该Context并没有和实际的ApplicationInfo绑定。而第二次执行init前,先利用Context和PKMS交互得到一个实际ApplicationInfo,然后再通过init将此Context和ApplicationInfo绑定。

1.ApplicationThreadNative实现了IApplicationThread接口。从该接口定义的函数可知,AMS通过它可以和应用进程进行交互,例如,AMS启动一个Activity的时候会调用该接口的scheduleLaunchActivity函数

2.ActivityThread通过成员变量mAppThread指向它的内部类ApplicationThread,而ApplicationThread从ApplicationThreadNative派生

3.IApplicationThread的Binder服务端在应用进程中,因为AMS需要监听应用进程的死亡通知。

4.有了IApplicationThread接口,AMS就可以和应用进程交互了。

public final void scheduleStopActivity(IBinder token, boolean showWindow,
        int configChanges) {
   sendMessage(
        showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,
        token, 0, configChanges);
}

当AMS想要停止(stop)一个Activity时,会调用对应进程IApplicationThread Binder客户端的scheduleStopActivity函数。该函数服务端实现的就是向ActivityThread所在线程发送一个消息。在应用进程中,ActivityThread运行在主线程中,所以这个消息最终在主线程被处理。Activity的onStop函数页将在主线程中被处理。

IApplication Thread仅仅是AMS和另外一个进程交互的接口,除此之外,AMS还需要更多的有关该进程的信息。在AMS中,进程的信息都保存在ProcessRecord数据结构中。

final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
        boolean isolated, int isolatedUid) {
    String proc = customProcess != null ? customProcess : info.processName;
    BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
    final int userId = UserHandle.getUserId(info.uid);
    int uid = info.uid;
    if (isolated) {
        if (isolatedUid == 0) {
            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;
                }
            }
        } else {
            // Special case for startIsolatedProcess (internal only), where
            // the uid of the isolated process is specified by the caller.
            uid = isolatedUid;
        }
    }
    final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);
    if (!mBooted && !mBooting
            && userId == UserHandle.USER_OWNER
            && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
        r.persistent = true;
    }
    addProcessNameLocked(r);
    return r;
}
ProcessRecord(BatteryStatsImpl _batteryStats, ApplicationInfo _info,
        String _processName, int _uid) {
    mBatteryStats = _batteryStats;
    info = _info;
    isolated = _info.uid != _uid;
    uid = _uid;
    userId = UserHandle.getUserId(_uid);
    processName = _processName;
    pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.versionCode));
    maxAdj = ProcessList.UNKNOWN_ADJ;
    curRawAdj = setRawAdj = -100;
    curAdj = setAdj = -100;
    persistent = false;
    removed = false;
    lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
}

ProcessRecord除保存和应用进程通信的IApplicationThread对象外,还保存了进程名、不同状态对应的Oom_adj值及一个ApplicationInfo。一个进程虽然可运行多个Application,但是ProcessRecord一般保存该进程中先运行的那个Application的ApplicationInfo。现在,创建了一个ProcessRecord对象,该对象对应的进程为system_server。

AMS的setSystemProcess的工作

1.注册AMS、meminfo、gfxinfo等服务到ServiceManager中

2.根据PKMS返回的ApplicationInfo初始化Android运行环境,并创建一个代表system_server进程的ProcessRecord,从此,system_server进程也并入AMS的管理范围内。

public final void installSystemProviders() {
    List<ProviderInfo> providers;
    synchronized (this) {
        ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);
        providers = 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);
    }

    mCoreSettingsObserver = new CoreSettingsObserver(this);

    //mUsageStatsService.monitorPackages();
}
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
    List<ProviderInfo> providers = null;
    try {
        ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager().
            queryContentProviders(app.processName, app.uid,
                    STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
        providers = slice != null ? slice.getList() : null;
    } catch (RemoteException ex) {
    }
    if (DEBUG_MU) Slog.v(TAG_MU,
            "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
    int userId = app.userId;
    if (providers != null) {
        int N = providers.size();
        app.pubProviders.ensureCapacity(N + app.pubProviders.size());
        for (int i=0; i<N; i++) {
            ProviderInfo cpi =
                (ProviderInfo)providers.get(i);
            boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                    cpi.name, cpi.flags);
            if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_OWNER) {
                // This is a singleton provider, but a user besides the
                // default user is asking to initialize a process it runs
                // in...  well, no, it doesn't actually run in this process,
                // it runs in the process of the default user.  Get rid of it.
                providers.remove(i);
                N--;
                i--;
                continue;
            }

            ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
            ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
            if (cpr == null) {
                cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
                mProviderMap.putProviderByClass(comp, cpr);
            }
            if (DEBUG_MU) Slog.v(TAG_MU,
                    "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
            app.pubProviders.put(cpi.name, cpr);
            if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
                // Don't add this if it is a platform component that is marked
                // to run in multiple processes, because this is actually
                // part of the framework so doesn't make sense to track as a
                // separate apk in the process.
                app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
                        mProcessStats);
            }
            ensurePackageDexOpt(cpi.applicationInfo.packageName);
        }
    }
    return providers;
}
    public final void installSystemProviders() {
        List<ProviderInfo> providers;
        synchronized (this) {
            ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);
            providers = 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);
        }

        mCoreSettingsObserver = new CoreSettingsObserver(this);

        //mUsageStatsService.monitorPackages();
    }
@Override
    public ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
            int uid, int flags) {
        ArrayList<ProviderInfo> finalList = null;
        // reader
        synchronized (mPackages) {
            final Iterator<PackageParser.Provider> i = mProviders.mProviders.values().iterator();
            final int userId = processName != null ?
                    UserHandle.getUserId(uid) : UserHandle.getCallingUserId();
            while (i.hasNext()) {
                final PackageParser.Provider p = i.next();
                PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
                if (ps != null && p.info.authority != null
                        && (processName == null
                                || (p.info.processName.equals(processName)
                                        && UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
                        && mSettings.isEnabledLPr(p.info, flags, userId)
                        && (!mSafeMode
                                || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
                    if (finalList == null) {
                        finalList = new ArrayList<ProviderInfo>(3);
                    }
                    ProviderInfo info = PackageParser.generateProviderInfo(p, flags,
                            ps.readUserState(userId), userId);
                    if (info != null) {
                        finalList.add(info);
                    }
                }
            }
        }

        if (finalList != null) {
            Collections.sort(finalList, mProviderInitOrderSorter);
            return new ParceledListSlice<ProviderInfo>(finalList);
        }

        return null;
    }

AMS保存ProviderInfo的原因是它要管理ContentProvider。ProcessRecord保存ProviderInfo的原因是ContentProvider最终要落实到一个进程中,其实也是为了方便AMS管理,例如该进程一旦退出,AMS需要把其中的ContentProvider信息从系统中去除。

AMS及ProcessRecord均使用了一个新的数据结构ContentProviderRecord来管理ContentProvider。

1.ContentProviderRecord从ContentProviderHolder派生,内部保存了ProviderInfo、该Provider所驻留的进程ProcessRecord,以及使用该ContentProvider的客户端进程ProcessRecord(即clients成员变量)

2.AMS的mProviderByClass成员变量及ProcessRecord的pubProviders成员变量均以ComponentName为key来保存对应的ContentProviderRecrod对象。

public final void installSystemProviders(List<ProviderInfo> providers) {
    if (providers != null) {
        installContentProviders(mInitialApplication, providers);
    }
}
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) {
    }
}

installContentProviders实际上是标准的ContentProvider安装时调用的程序。安装ContentProvider包括两方面的工作

1.先在ActivityThread中通过installProvider得到一个ContentProvider实例

2.向AMS发布这个ContentProvider实例。如此这般,一个APK中声明的ContentProvider才能发挥其该有的作用。

private IActivityManager.ContentProviderHolder installProvider(Context context,
        IActivityManager.ContentProviderHolder holder, ProviderInfo info,
        boolean noisy, boolean noReleaseNeeded, boolean stable) {
    ContentProvider localProvider = null;
    IContentProvider provider;
    if (holder == null || holder.provider == null) {
        if (DEBUG_PROVIDER || noisy) {
            Slog.d(TAG, "Loading provider " + info.authority + ": "
                    + info.name);
        }
        Context c = null;
        ApplicationInfo ai = info.applicationInfo;
        if (context.getPackageName().equals(ai.packageName)) {
            c = context;
        } else if (mInitialApplication != null &&
                mInitialApplication.getPackageName().equals(ai.packageName)) {
            c = mInitialApplication;
        } else {
            try {
                c = context.createPackageContext(ai.packageName,
                        Context.CONTEXT_INCLUDE_CODE);
            } catch (PackageManager.NameNotFoundException e) {
                // Ignore
            }
        }
        if (c == null) {
            Slog.w(TAG, "Unable to get context for package " +
                  ai.packageName +
                  " while loading content provider " +
                  info.name);
            return null;
        }
        try {
            final java.lang.ClassLoader cl = c.getClassLoader();
            localProvider = (ContentProvider)cl.
                loadClass(info.name).newInstance();
            provider = localProvider.getIContentProvider();
            if (provider == null) {
                Slog.e(TAG, "Failed to instantiate class " +
                      info.name + " from sourceDir " +
                      info.applicationInfo.sourceDir);
                return null;
            }
            if (DEBUG_PROVIDER) Slog.v(
                TAG, "Instantiating local provider " + info.name);
            // XXX Need to create the correct context for this provider.
            localProvider.attachInfo(c, info);
        } catch (java.lang.Exception e) {
            if (!mInstrumentation.onException(null, e)) {
                throw new RuntimeException(
                        "Unable to get provider " + info.name
                        + ": " + e.toString(), e);
            }
            return null;
        }
    } else {
        provider = holder.provider;
        if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
                + info.name);
    }

    IActivityManager.ContentProviderHolder retHolder;

    synchronized (mProviderMap) {
        if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
                + " / " + info.name);
        IBinder jBinder = provider.asBinder();
        if (localProvider != null) {
            ComponentName cname = new ComponentName(info.packageName, info.name);
            ProviderClientRecord pr = mLocalProvidersByName.get(cname);
            if (pr != null) {
                if (DEBUG_PROVIDER) {
                    Slog.v(TAG, "installProvider: lost the race, "
                            + "using existing local provider");
                }
                provider = pr.mProvider;
            } else {
                holder = new IActivityManager.ContentProviderHolder(info);
                holder.provider = provider;
                holder.noReleaseNeeded = true;
                pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                mLocalProviders.put(jBinder, pr);
                mLocalProvidersByName.put(cname, pr);
            }
            retHolder = pr.mHolder;
        } else {
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
            if (prc != null) {
                if (DEBUG_PROVIDER) {
                    Slog.v(TAG, "installProvider: lost the race, updating ref count");
                }
                // We need to transfer our new reference to the existing
                // ref count, releasing the old one...  but only if
                // release is needed (that is, it is not running in the
                // system process).
                if (!noReleaseNeeded) {
                    incProviderRefLocked(prc, stable);
                    try {
                        ActivityManagerNative.getDefault().removeContentProvider(
                                holder.connection, stable);
                    } catch (RemoteException e) {
                        //do nothing content provider object is dead any way
                    }
                }
            } else {
                ProviderClientRecord client = installProviderAuthoritiesLocked(
                        provider, localProvider, holder);
                if (noReleaseNeeded) {
                    prc = new ProviderRefCount(holder, client, 1000, 1000);
                } else {
                    prc = stable
                            ? new ProviderRefCount(holder, client, 1, 0)
                            : new ProviderRefCount(holder, client, 0, 1);
                }
                mProviderRefCountMap.put(jBinder, prc);
            }
            retHolder = prc.holder;
        }
    }

    return retHolder;
} 

1.ContentProvider类本身只是一个容器,而跨进程调用的支持是通过内部类Transport实现。Transport从ContentProviderNative派生,而ContentProvider的成员变量mTransport指向Transport对象。ContentProvider的getIContentProvider函数即返回mTransport成员变量

2.ContentProviderNative从Binder派生,并实现了IContentProvider接口。其内部类ContentProviderProxy是供客户端使用的

3.ProviderClientRecord是ActivityThread提供的用于保存ContentProvider信息的一个数据结构。它的mLocalProvider用于保存ContentProvider对象,mProvider用于保存IContentProvider对象。另外一个成员mName用于保持该ContentProvider的一个authority。注意,ContentProvider可以定义多个authority,就好像一个网站有多个域名一样。

public final void publishContentProviders(IApplicationThread caller,
        List<ContentProviderHolder> providers) {
    if (providers == null) {
        return;
    }

    enforceNotIsolatedCaller("publishContentProviders");
    synchronized (this) {
        final ProcessRecord r = getRecordForAppLocked(caller);
        if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
        if (r == null) {
            throw new SecurityException(
                    "Unable to find app for caller " + caller
                  + " (pid=" + Binder.getCallingPid()
                  + ") when publishing content providers");
        }

        final long origId = Binder.clearCallingIdentity();

        final int N = providers.size();
        for (int i=0; i<N; i++) {
            ContentProviderHolder src = providers.get(i);
            if (src == null || src.info == null || src.provider == null) {
                continue;
            }
            ContentProviderRecord dst = r.pubProviders.get(src.info.name);
            if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
            if (dst != null) {
                ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
                mProviderMap.putProviderByClass(comp, dst);
                String names[] = dst.info.authority.split(";");
                for (int j = 0; j < names.length; j++) {
                    mProviderMap.putProviderByName(names[j], dst);
                }

                int NL = mLaunchingProviders.size();
                int j;
                for (j=0; j<NL; j++) {
                    if (mLaunchingProviders.get(j) == dst) {
                        mLaunchingProviders.remove(j);
                        j--;
                        NL--;
                    }
                }
                synchronized (dst) {
                    dst.provider = src.provider;
                    dst.proc = r;
                    dst.notifyAll();
                }
                updateOomAdjLocked(r);
                maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                        src.info.authority);
            }
        }

        Binder.restoreCallingIdentity(origId);
    }
}

瀑布lishContentProviders的工作流程

1.先根据调用者的PID找到对应的ProcessRecord对象

2.该ProcessRecord的pubProviders中保存了ContentProviderRecord信息。该信息由前面介绍的AMS的generateApplicationProvidersLocked函数根据Package本身的信息生成。此处将判断要发布的ContentProvider是否由该Package声明

3.如果判断返回成功,则将该ContentProvider及其对应的authority加到mProvidersByName中。注意,AMS中还有一个mProvidersByClass变量,该变量以ContentProvider的ComponentName为key,即系统提供两种方式找到某一个ContentProvider,一种是通过authority,另一种方式就是指明ComponentName。

4.mLaunchProviders和最后的notifyAll函数用于通知那些等待ContentProvider所在进程启动的客户端进程。例如,进程A要查询一个数据库,需要通过进程B中的某个ContentProvider来实施。如果B还未启动,那么AMS就需要先启动B。在这段时间内,A需要等待B启动并注册对应的ContentProvider。B一旦完成注册,就需要告知A退出等待以继续后续的查询工作。

public void systemReady(final Runnable goingCallback) {
    synchronized(this) {
        if (mSystemReady) {
            // If we're done calling all the receivers, run the next "boot phase" passed in
            // by the SystemServer
            if (goingCallback != null) {
                goingCallback.run();
            }
            return;
        }

        mLocalDeviceIdleController
                = LocalServices.getService(DeviceIdleController.LocalService.class);

        // Make sure we have the current profile info, since it is needed for
        // security checks.
        updateCurrentProfileIdsLocked();

        mRecentTasks.clear();
        mRecentTasks.addAll(mTaskPersister.restoreTasksLocked());
        mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
        mTaskPersister.startPersisting();

        // Check to see if there are any update receivers to run.
        if (!mDidUpdate) {
            if (mWaitingUpdate) {
                return;
            }
            final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
            mWaitingUpdate = deliverPreBootCompleted(new Runnable() {
                public void run() {
                    synchronized (ActivityManagerService.this) {
                        mDidUpdate = true;
                    }
                    showBootMessage(mContext.getText(
                            R.string.android_upgrading_complete),
                            false);
                    writeLastDonePreBootReceivers(doneReceivers);
                    systemReady(goingCallback);
                }
            }, doneReceivers, UserHandle.USER_OWNER);

            if (mWaitingUpdate) {
                return;
            }
            mDidUpdate = true;
        }

        mAppOpsService.systemReady();
        mSystemReady = true;
    }

    ArrayList<ProcessRecord> procsToKill = null;
    synchronized(mPidsSelfLocked) {
        for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
            ProcessRecord proc = mPidsSelfLocked.valueAt(i);
            if (!isAllowedWhileBooting(proc.info)){
                if (procsToKill == null) {
                    procsToKill = new ArrayList<ProcessRecord>();
                }
                procsToKill.add(proc);
            }
        }
    }

    synchronized(this) {
        if (procsToKill != null) {
            for (int i=procsToKill.size()-1; i>=0; i--) {
                ProcessRecord proc = procsToKill.get(i);
                Slog.i(TAG, "Removing system update proc: " + proc);
                removeProcessLocked(proc, true, false, "system update done");
            }
        }

        // Now that we have cleaned up any update processes, we
        // are ready to start launching real processes and know that
        // we won't trample on them any more.
        mProcessesReady = true;
    }

    Slog.i(TAG, "System now ready");
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
        SystemClock.uptimeMillis());

    synchronized(this) {
        // Make sure we have no pre-ready processes sitting around.

        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            ResolveInfo ri = mContext.getPackageManager()
                    .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
                            STOCK_PM_FLAGS);
            CharSequence errorMsg = null;
            if (ri != null) {
                ActivityInfo ai = ri.activityInfo;
                ApplicationInfo app = ai.applicationInfo;
                if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
                    mTopAction = Intent.ACTION_FACTORY_TEST;
                    mTopData = null;
                    mTopComponent = new ComponentName(app.packageName,
                            ai.name);
                } else {
                    errorMsg = mContext.getResources().getText(
                            com.android.internal.R.string.factorytest_not_system);
                }
            } else {
                errorMsg = mContext.getResources().getText(
                        com.android.internal.R.string.factorytest_no_action);
            }
            if (errorMsg != null) {
                mTopAction = null;
                mTopData = null;
                mTopComponent = null;
                Message msg = Message.obtain();
                msg.what = SHOW_FACTORY_ERROR_MSG;
                msg.getData().putCharSequence("msg", errorMsg);
                mUiHandler.sendMessage(msg);
            }
        }
    }

    retrieveSettings();
    loadResourcesOnSystemReady();

    synchronized (this) {
        readGrantedUriPermissionsLocked();
    }

    if (goingCallback != null) goingCallback.run();

    mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
            Integer.toString(mCurrentUserId), mCurrentUserId);
    mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
            Integer.toString(mCurrentUserId), mCurrentUserId);
    mSystemServiceManager.startUser(mCurrentUserId);

    synchronized (this) {
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            try {
                List apps = AppGlobals.getPackageManager().
                    getPersistentApplications(STOCK_PM_FLAGS);
                if (apps != null) {
                    int N = apps.size();
                    int i;
                    for (i=0; i<N; i++) {
                        ApplicationInfo info
                            = (ApplicationInfo)apps.get(i);
                        if (info != null &&
                                !info.packageName.equals("android")) {
                            addAppLocked(info, false, null /* ABI override */);
                        }
                    }
                }
            } catch (RemoteException ex) {
                // pm is in same process, this will never happen.
            }
        }

        // Start up initial activity.
        mBooting = true;
        startHomeActivityLocked(mCurrentUserId, "systemReady");

        try {
            if (AppGlobals.getPackageManager().hasSystemUidErrors()) {
                Slog.e(TAG, "UIDs on the system are inconsistent, you need to wipe your"
                        + " data partition or your device will be unstable.");
                mUiHandler.obtainMessage(SHOW_UID_ERROR_MSG).sendToTarget();
            }
        } catch (RemoteException e) {
        }

        if (!Build.isBuildConsistent()) {
            Slog.e(TAG, "Build fingerprint is not consistent, warning user");
            mUiHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget();
        }

        long ident = Binder.clearCallingIdentity();
        try {
            Intent intent = new Intent(Intent.ACTION_USER_STARTED);
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                    | Intent.FLAG_RECEIVER_FOREGROUND);
            intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
            broadcastIntentLocked(null, null, intent,
                    null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                    null, false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);
            intent = new Intent(Intent.ACTION_USER_STARTING);
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
            intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
            broadcastIntentLocked(null, null, intent,
                    null, new IIntentReceiver.Stub() {
                        @Override
                        public void performReceive(Intent intent, int resultCode, String data,
                                Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                                throws RemoteException {
                        }
                    }, 0, null, null,
                    new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
                    null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
        } catch (Throwable t) {
            Slog.wtf(TAG, "Failed sending first user broadcasts", t);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        mStackSupervisor.resumeTopActivitiesLocked();
        sendUserSwitchBroadcastsLocked(-1, mCurrentUserId);
    }
}

systemReady三阶段的工作

1.第一阶段:发送并处理与PRE_BOOT_COMPLETED广播相关的事情

2.第二阶段:(1)杀死那些在AMS还未启动完毕就先启动的应用进程。注意,这些进程一定是APK所在的java进程,因为只有应用进程才会向AMS注册,而一般Native(例如mediaserver)进程是不会向AMS注册的

      (2)从Setting数据库获取配置信息,目前只取4个配置参数,分别是debug_app(设置需要debug的app的名称)、wait_for_debugger(如果为1,则等待调试器,否则正常启动debug_app)、always_finish_activities(当一个activity不再有地方使用时,是否立即对它执行destroy)、font_scale(用于控制字体放大倍数,这是android4.0新增的功能)。以上配置项由Setting数据库的system表提供

3.第三阶段:(1)调用systemReady设置的回调对象goingCallback的run函数

      (2)启动那些声明了persistent的APK

      (3)启动桌面

启动Home桌面

final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
    if (mStackSupervisor.inResumeTopActivity) {
        // Don't even start recursing.
        return false;
    }

    boolean result = false;
    try {
        // Protect against recursion.
        mStackSupervisor.inResumeTopActivity = true;
        if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
            mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
            mService.updateSleepIfNeededLocked();
        }
        result = resumeTopActivityInnerLocked(prev, options);
    } finally {
        mStackSupervisor.inResumeTopActivity = false;
    }
    return result;
}
boolean startHomeActivityLocked(int userId, String reason) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            // We are running in factory test mode, but unable to find
            // the factory test app, so just sit around displaying the
            // error message and don't try to start anything.
            return false;
        }
        Intent intent = getHomeIntent();
        ActivityInfo aInfo =
            resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
        if (aInfo != null) {
            intent.setComponent(new ComponentName(
                    aInfo.applicationInfo.packageName, aInfo.name));
            // Don't do this if the home app is currently being
            // instrumented.
            aInfo = new ActivityInfo(aInfo);
            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
            ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid, true);
            if (app == null || app.instrumentationClass == null) {
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                mStackSupervisor.startHomeActivity(intent, aInfo, reason);
            }
        }

        return true;
    }

AMS总结

1.main函数:创建AMS实例,其中最重要的工作是创建android运行环境,得到一个ActivityThread和Context对象

2.AMS的setSystemProcess函数:该函数注册AMS和meminfo等服务到ServiceManager中,另外,它为system_server创建了一个ProcessRecord对象。由于AMS是Java世界的进程管理及调度中心,要做到对java进程一视同仁,尽管system_server贵为系统进程,此时也不得不将其并入AMS的管理范围内

3.AMS的installSystemProviders函数:为system_server加载SettingProvider

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

@Override
public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
    enforceNotIsolatedCaller("startActivityAndWait");
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
            false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
    WaitResult res = new WaitResult();
    // TODO: Switch to user app stacks here.
    mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
            null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,
            options, false, userId, null, null);
    return res;
}

 

posted @ 2017-07-14 17:54  嘉禾世兴  阅读(1136)  评论(0编辑  收藏  举报