android AMS 详解三

文章出处:https://blog.csdn.net/shift_wwx/article/details/46427633

接着之前两篇

android AMS 详解一

android AMS 详解二

接着总结:

ActivityManagerService.installSystemProviders()

    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();
    }

从函数表面是看,获取system进程的providers,然后过滤出system的providers进行install。

1)这里的app是在之前 android AMS 详解二 的setSystemProcess中提到过的:

mSelf.mProcessNames.put(app.processName, app.uid, app);

显然app.processName就是system,app.uid指的也是system_uid。

2)通过函数generateApplicationProvidersLocked获取providers

    private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
        List<ProviderInfo> providers = null;
        try {
            providers = AppGlobals.getPackageManager().
                queryContentProviders(app.processName, app.uid,
                        STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
        } 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) != 0) {
                    // 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, mProcessStats);
                }
                ensurePackageDexOpt(cpi.applicationInfo.packageName);
            }
        }
        return providers;
    }

(1)AppGlobals.getPackageManager()

    public static IPackageManager getPackageManager() {
        return ActivityThread.getPackageManager();
    }

接着:

    public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
            return sPackageManager;
        }
        IBinder b = ServiceManager.getService("package");
        //Slog.v("PackageManager", "default service binder = " + b);
        sPackageManager = IPackageManager.Stub.asInterface(b);
        //Slog.v("PackageManager", "default service = " + sPackageManager);
        return sPackageManager;
    }

似曾相识过吧,在
ActivityManagerService (二)setSystemProcess中提到过:

ApplicationInfo info =mSelf.mContext.getPackageManager().getApplicationInfo("android", STOCK_PM_FLAGS);

不过这里是通过context获取PMS:

    @Override
    public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;
        }

        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm != null) {
            // Doesn't matter if we make more than one instance.
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }

        return null;
    }

不过最终还是会调用到ActivityThread.getPackageManager();我想这里没有用AMS中mSystemThread应该是为了区分system和非system的app吧。

static IPackageManager sPackageManager;

所以用的是一个PMS。

(2)queryContentProviders

    public List<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 finalList;
    }

这个函数中:

final Iterator<PackageParser.Provider> i = mProviders.mProviders.values().iterator();

不知道怎么来的,需要跟一下PMS.main,对于PMS详细过程,后期会总结,这里应该是通过PMS解析后搜集了所有的providers。

过滤条件比较多,authority不能为null,processName是system,uid是system_uid,flags的第0 bit位是FLAG_SYSTEM。

(3)app.pubProviders.ensureCapacity(N + app.pubProviders.size());

更新pubProviders的size。

final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<String, ContentProviderRecord>();

(4)处理provider

mProviderMap.putProviderByClass(comp, cpr);//加到AMS中的ProviderMap中

final ProviderMap mProviderMap;//mProviderMap是final的

app.pubProviders.put(cpi.name, cpr);//加到ProcessRecord里面的pubProviders

final ArrayMap<String, ContentProviderRecord> pubProviders
    = new ArrayMap<String, ContentProviderRecord>();

app.addPackage(cpi.applicationInfo.packageName, mProcessStats);//将package加到ProcessRecord中的pkgList

    public boolean addPackage(String pkg, ProcessStatsService tracker) {
        if (!pkgList.containsKey(pkg)) {
            if (baseProcessTracker != null) {//baseProcessTracker在之前的AMS.setSystemProcess中的makeActive中初始化过
                ProcessStats.ProcessState state = tracker.getProcessStateLocked(
                        pkg, info.uid, processName);
                pkgList.put(pkg, state);
                if (state != baseProcessTracker) {
                    state.makeActive();
                }
            } else {
                pkgList.put(pkg, null);
            }
            return true;
        }
        return false;
    }

结合之前的AMS.setSystemProcess,这时ProcessRecord就有两个package在里面了,一个是framework-res.apk中所指的android package,另一个就是这里的process name 是system,uid是system_uid的provider。

看一下AMS和ProcessRecord中保存SettingsProvider的数据结构。

《android AMS 详解三》

弄了半天,这样的provider在andorid系统有中有哪些呢?为什么要在AMS初始化的前期一定要初始化提出来这些provider,经过检查发现了这样的provider:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.providers.settings"
        coreApp="true"
        android:sharedUserId="android.uid.system">

    <application android:allowClearUserData="false"
                 android:label="@string/app_label"
                 android:process="system"
                 android:backupAgent="SettingsBackupAgent"
                 android:killAfterRestore="false"
                 android:icon="@mipmap/ic_launcher_settings">

    <!-- todo add: android:neverEncrypt="true" -->

        <provider android:name="SettingsProvider" android:authorities="settings"
                  android:multiprocess="false"
                  android:exported="true"
                  android:writePermission="android.permission.WRITE_SETTINGS"
                  android:initOrder="100" />

    </application>
</manifest>

看到package name就知道了,是SettingsProvider.apk。至于SettingsProvider具体作用这里不做解释,一些系统的默认参数都是通过这里设置,通过db来实现进程间数据共享等等。

3)mSystemThread.installSystemProviders(providers);

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

context是上面传进来的mInitialApplication,其实就是mSystemContext。

先不管ContextProviderHolder是什么,来看看获取这个cph的地方,installProvider:

    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)传进来的holder是null,所以,直接进入if条件语句块。

然后试图确认packageName是否和mSystemContext的packageName一样,显然不一样,一个是com.android.providers.settings,一个android。
所以,索性创建了provider自己的context:

try {
    c = context.createPackageContext(ai.packageName,
            Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
    // Ignore
}

这个函数不去详细说明,主要就是通过packageName构造一个LoadedApk,通过context init来创建一个context返回。

(2)provider = localProvider.getIContentProvider();//localProvider完全可以看成是SettingsProvider

    public IContentProvider getIContentProvider() {
        return mTransport;
    }
 private Transport mTransport = new Transport();
class Transport extends ContentProviderNative {
    ......
}
abstract public class ContentProviderNative extends Binder implements IContentProvider {
    ......
}

集合provider定义的地方:

IContentProvider provider;

provider是个Binder,后面继续说明。

(3)localProvider.attachInfo(c, info);

    public void attachInfo(Context context, ProviderInfo info) {
        attachInfo(context, info, false);
    }

    private void attachInfo(Context context, ProviderInfo info, boolean testing) {
        /*
         * We may be using AsyncTask from binder threads.  Make it init here
         * so its static handler is on the main thread.
         */
        AsyncTask.init();

        mNoPerms = testing;

        /*
         * Only allow it to be set once, so after the content service gives
         * this to us clients can't change it.
         */
        if (mContext == null) {
            mContext = context;
            if (context != null) {
                mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
                        Context.APP_OPS_SERVICE);
            }
            mMyUid = Process.myUid();
            if (info != null) {
                setReadPermission(info.readPermission);
                setWritePermission(info.writePermission);
                setPathPermissions(info.pathPermissions);
                mExported = info.exported;
            }
            ContentProvider.this.onCreate();
        }
    }

创建AppOpsManager,设置SettingProvider的mMyUid,设置读写权限,设置path权限,设置mExported,最后回调SettingsProvider的onCreate函数。原来SettingsProvider在这里就创建ok了。

(4)IActivityManager.ContentProviderHolder retHolder;
可以说之前的都是初始化准备工作,这里才第一次创建ContentProviderHolder 对象。当然,局部的对象,是不可能直接返回的。

(5)ProviderClientRecord pr = mLocalProvidersByName.get(cname);

之前分析过了,在generateApplicationProvidersLocked中解析Provider的时候,只是在AMS和ProcessRecord里面有保存,ActivityThread里面是没有保存的,所以这里pr是null。

所以,会实例一个ContentProviderHolder。最后installProvider方法调用installProviderAuthoritiesLocked方法构造一个ProviderClientRecord对象,并添加到mProviderMap、mLocalProviders和mLocalProvidersByName中,这三个ArraryMap可以通过不同键值快速找到对象的ProviderClientRecord对象。最后返回ContentProviderHolder。AcitivytThread中保存SettingsProvider的信息如下:

《android AMS 详解三》

返回installContentProviders,既然ContentProviderHolder已经ok了,接着看下一步:

ActivityManagerNative.getDefault().publishContentProviders(
    getApplicationThread(), results);
    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);
                }
            }

            Binder.restoreCallingIdentity(origId);
        }
    }

(1)第一个参数getApplicationThread()

final ApplicationThread mAppThread = new ApplicationThread();

在构造mSystemThread的时候构造的,具体的在
android AMS 详解二 中提到过。

(2)第二个参数就是之前创造的ContentProviderHolder

getRecordForAppLocked从mLruProcesses链表中查找并返回我们前面创建的ProcessRecord对象,我们知道在generateApplicationProvidersLocked方法中,我们将从PMS

得到的SettingsProvider信息已经添加到ProcessRecord的pubProviders数组中了,这里将provider信息添加到mProviderMap中,并从mLaunchingProviders(表示待启动的

provider列表)中移除已经启动的provider。

最后回到installSystemProviders方法中,注册一个ContentObserver来监听Settings.Secure.LONG_PRESS_TIMEOUT的变化并调用UsageStatsService去监听package的使用状态。

到这里AMS的installSystemProviders就总结完了。后期会进一步的完善。

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