《深入理解Android2》读书笔记

Posted 嘉禾世兴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《深入理解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 " +《深入理解Android2》读书笔记

《深入理解Android2》读书笔记

《深入理解Android2》读书笔记

《深入理解计算机系统》 Chapter 7 读书笔记

《深入理解JVM虚拟机》读书笔记

java内存区域——深入理解JVM读书笔记