从系统看ContentProvider

基础知识

基于Android 12.0

一些概念

framework层ContentProvider相关逻辑主要在AMS类中(android 12.0+在ContentProviderHelper中),代表一个provider的是ContentProviderRecord

  1. ContentProvider通过uri来标识其他应用要访问的数据,通过ContentResolver的增、删、改、查来实现对共享数据的操作,通过注册ContentObserver来监听数据的变化。
  2. ContentProvider是一个抽象类,主要有onCreate()、query()、insert()、delete()、update()、getType()等方法。
  3. ContentProvider对底层的数据存储方式没有任何要求,可以是sqlite、xml文件、表格等。

常用命令

  1. 查询:adb shell content query --uri content://settings/settings
  2. 查看系统所有providers: adb shell dumpsys activity providers
Published single-user content providers (by class):
  * ContentProviderRecord{8675171 u0 com.android.providers.telephony/.TelephonyProvider}
    package=com.android.providers.telephony process=com.android.phone
    proc=ProcessRecord{78558d2 8295:com.android.phone/1001}
    uid=1001 provider=android.content.ContentProviderProxy@d344b56
    singleton=true
    authority=telephony
Published user 0 content providers (by class):
  * ContentProviderRecord{4636c8d u0 com.android.camera/.provider.SplashProvider}
    package=com.android.camera process=com.android.camera
    proc=ProcessRecord{3041928 2751:com.android.camera/u0a93}
    uid=10093 provider=android.content.ContentProviderProxy@b765e42
    authority=com.android.camera.splashProvider

一些相关类

ProcessRecord.java中持有ProcessProviderRecord的引用,保存当前进程所持有的provider的连接

    final ProcessProviderRecord mProviders;

ProcessProviderRecord.java 中持有ContentProviderConnection的列表

    private final ArrayList<ContentProviderConnection> mConProviders = new ArrayList<>();

访问provider失败的情况

user未解锁成功的情况下,去访问provider

抛出异常

04-29 18:50:13.156 1000 1618 2005 I am_crash: [3581,0,com.android.settings,684310085,java.lang.IllegalArgumentException,Unknown authority com.miui.securitycenter.remoteprovider,ContentResolver.java,2055]
04-29 18:50:21.620 radio 2309 2309 D CarrierSvcBindHelper: Received android.intent.action.USER_UNLOCKED

打印log

08-23 10:32:15.763 radio 13776 17512 W ActivityThread: Failed to find provider info for com.miui.idprovider (user not unlocked)

通过provider拉起进程时,该进程10s内未成功发布provider

访问provider的进程,刚拉起立刻被杀

MIUIROM-141335

06-11 14:56:44.789 1000 1699 1760 I ActivityManager: Start proc 9434:com.miui.securitycenter.remote/1000 for content provider {com.miui.securitycenter/com.miui.idprovider.IdProvider{color}} caller=com.yaofangwang.mall

06-11 14:56:44.809 1000 1699 2190 I am_proc_bound: [0,9434,com.miui.securitycenter.remote]

06-11 14:56:44.881 1000 1699 2190 I ActivityManager: Force stopping com.miui.securitycenter appid=1000 user=0: from process:com.miui.securitycenter.remote

06-11 14:56:44.882 1000 1699 2190 I am_kill : [0,9434,com.miui.securitycenter.remote,0,stop com.miui.securitycenter due to from process:com.miui.securitycenter.remote]

所以getContentProviderImpl等待耗时(20s)

06-11 14:56:55.925 1000 1699 1759 I am_wtf : [0,8787,system_server,-1,ActivityManager,Timeout waiting for provider com.miui.securitycenter/1000 for provider com.miui.idprovider providerRunning=false caller=com.yaofangwang.mall/11662]

app进程发生crash

MIUI-1948222

08-17 20:21:30.081 1000 1534 1737 I am_proc_start: [0,29540,10254,com.ct.client,content provider,{com.ct.client/cn.jpush.android.service.DownloadProvider{color}}]

08-17 20:21:30.092 1000 1534 4935 I am_proc_bound: [0,29540,com.ct.client]

08-17 20:21:37.735 10254 29540 29540 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x780 in tid 29540 (com.ct.client), pid 29540 (com.ct.client)

08-17 20:21:40.096 1000 1534 1734 I am_kill : [0,29540,com.ct.client,0,timeout publishing content providers]

08-17 20:23:32.706 1000 1534 1734 I am_wtf : [0,7799,system_server,-1,ActivityManager,Timeout waiting for provider com.ct.client/10254 for provider com.ct.client.DownloadProvider providerRunning=false caller=tv.yixia.bobo/10406]

app执行Application初始化耗时等

07-31 11:07:17.380 1000 1764 5722 E ActivityManager: Timeout waiting for provider com.sina.weibo/10266 for provider com.sina.weibo.spProvider providerRunning=false caller=com.sina.weibo.image/10266

07-31 11:07:17.380 10266 4767 4767 W BpBinder: Slow Binder: BpBinder transact took 20001 ms, interface=android.app.IActivityManager, code=20 oneway=false

07-31 11:07:17.638 10266 4767 4767 W Looper : Slow Looper main: Long Msg: seq=2 plan=11:06:57.243 late=11ms wall=20384ms running=100ms runnable=28ms io=94ms h=android.app.ActivityThread$H w=110

system server拦截通过provider拉起进程

安全中心限制通过小组件的形式拉起进程

08-16 15:28:58.260 1000 1575 6263 I com.android.server.am.ExtraActivityManagerService: MIUILOG- Reject widget call from com.mi.health
08-16 15:28:58.262 10235 23702 23728 E ActivityThread: Failed to find provider info for com.mi.health.provider.main

miui的低内存限制拉起进程等

07-20 15:59:20.920 1593 15808 D ExtraActivityManagerService: Reject userId= 0 caller= com.miui.gallery callee= com.miui.gallery class=com.miui.gallery.provider.GalleryProvider action=null wakeType=4, cause by low mem.
07-20 15:59:20.920 26195 26325 E ActivityThread: Failed to find provider info for com.miui.gallery.cloud.provider

流程梳理

app端流程

app端可通过如下调用链最终调到AMS获取provider
ContentResolver::call -> ApplicationContentResolver::acquireProvider -> ActivityThread::acquireProvider
app会通过ContentResolver的call方法来实现读/写接口

    @Override
    public final @Nullable Bundle call(@NonNull String authority, @NonNull String method,
            @Nullable String arg, @Nullable Bundle extras) {
        Objects.requireNonNull(authority, "authority");
        Objects.requireNonNull(method, "method");

        try {
            if (mWrapped != null) return mWrapped.call(authority, method, arg, extras);
        } catch (RemoteException e) {
            return null;
        }

        IContentProvider provider = acquireProvider(authority);
		// 获取不到provider,抛出如上log的异常
        if (provider == null) {
            throw new IllegalArgumentException("Unknown authority " + authority);
        }
        try {
			// call流程
            final Bundle res = provider.call(mPackageName, mAttributionTag, authority, method, arg,
                    extras);
            Bundle.setDefusable(res, true);
            return res;
        } catch (RemoteException e) {
            return null;
        } finally {
			// 释放provider
            releaseProvider(provider);
        }
    }

ContextImpl的内部类ApplicationContentResolver继承自ContentResolver,最终还是调用到ActivityThread中的逻辑

        @Override
        @UnsupportedAppUsage
        protected IContentProvider acquireProvider(Context context, String auth) {
            return mMainThread.acquireProvider(context,
                    ContentProvider.getAuthorityWithoutUserId(auth),
                    resolveUserIdFromAuthority(auth), true);
        }

ActivityThread中的逻辑如下:

  1. 存在直接获取
  2. 可以直接通过AMS查询到
  3. 等待对端provider发布成功,超时20s
  4. 20s超时或user未解锁,provider会为null
        @UnsupportedAppUsage
    public final IContentProvider acquireProvider(
            Context c, String auth, int userId, boolean stable) {
		// 已存在则直接返回
        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
        if (provider != null) {
            return provider;
        }
		// 根据auth,userId封装获取provider key
        ContentProviderHolder holder = null;
        final ProviderKey key = getGetProviderKey(auth, userId);
        try {
            synchronized (key) {
				// 不存在通过AMS查询
                holder = ActivityManager.getService().getContentProvider(
                        getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
            	// provider的holder不为null,但是provider为null且holder不是本地holder
                if (holder != null && holder.provider == null && !holder.mLocal) {
                    synchronized (key.mLock) {
						// 等待provider进程发布provider完成,超时时间为20s
						// 会在ContentProviderRecord的notifyContentProviderPublishStatus方法回调时notify
                        key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
						// notify后,将key中的holder赋值给holder
                        holder = key.mHolder;
                    }
					// 如果超时仍未收到notify,holder会为null
                    if (holder != null && holder.provider == null) {
                        // probably timed out
                        holder = null;
                    }
                }
            }
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        } catch (InterruptedException e) {
            holder = null;
        } finally {
            // Clear the holder from the key since the key itself is never cleared.
            synchronized (key.mLock) {
                key.mHolder = null;
            }
        }
		// 打印失败log,user未解锁情况大部分不允许访问provider
        if (holder == null) {
            if (UserManager.get(c).isUserUnlocked(userId)) {
                Slog.e(TAG, "Failed to find provider info for " + auth);
            } else {
                Slog.w(TAG, "Failed to find provider info for " + auth + " (user not unlocked)");
            }
            return null;
        }
		// 在本进程中installProvider
        holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
        return holder.provider;
    }

    @UnsupportedAppUsage
    public final IContentProvider acquireExistingProvider(
            Context c, String auth, int userId, boolean stable) {
        synchronized (mProviderMap) {
			// 通过key获取provider clent 对象
            final ProviderKey key = new ProviderKey(auth, userId);
            final ProviderClientRecord pr = mProviderMap.get(key);
            if (pr == null) {
                return null;
            }

            IContentProvider provider = pr.mProvider;
			// 对端进程挂掉了
            IBinder jBinder = provider.asBinder();
            if (!jBinder.isBinderAlive()) {
                Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
                        + ": existing object's process dead");
                handleUnstableProviderDiedLocked(jBinder, true);
                return null;
            }
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
			// 增加引用计数
            if (prc != null) {
                incProviderRefLocked(prc, stable);
            }
            return provider;
        }
    }
    @UnsupportedAppUsage
    private ContentProviderHolder installProvider(Context context,
            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;
            }

            if (info.splitName != null) {
                try {
                    c = c.createContextForSplit(info.splitName);
                } catch (NameNotFoundException e) {
                    throw new RuntimeException(e);
                }
            }
            if (info.attributionTags != null && info.attributionTags.length > 0) {
                final String attributionTag = info.attributionTags[0];
                c = c.createAttributionContext(attributionTag);
            }

            try {
                final java.lang.ClassLoader cl = c.getClassLoader();
                LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
                if (packageInfo == null) {
                    // System startup case.
                    packageInfo = getSystemContext().mPackageInfo;
                }
                localProvider = packageInfo.getAppFactory()
                        .instantiateProvider(cl, info.name);
                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);
        }

        ContentProviderHolder retHolder;

        synchronized (mProviderMap) {
            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 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");
                    }
                    if (!noReleaseNeeded) {
                        incProviderRefLocked(prc, stable);
                        try {
                            ActivityManager.getService().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;
    }

system server端流程

AMS中

    @Override
    public final ContentProviderHolder getContentProvider(
            IApplicationThread caller, String callingPackage, String name, int userId,
            boolean stable) {
        traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "getContentProvider: ", name);
        try {
           return mCpHelper.getContentProvider(caller, callingPackage, name, userId, stable);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
    }

ContentProviderHelper(android 12.0新出现的类)中处理流程

    ContentProviderHolder getContentProvider(IApplicationThread caller, String callingPackage,
            String name, int userId, boolean stable) {
        mService.enforceNotIsolatedCaller("getContentProvider");
		// caller不能为null
        if (caller == null) {
            String msg = "null IApplicationThread when getting content provider " + name;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }
        // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
        // with cross-user grant.
        final int callingUid = Binder.getCallingUid();
        if (callingPackage != null && mService.mAppOpsService.checkPackage(
                callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
            throw new SecurityException("Given calling package " + callingPackage
                    + " does not match caller's uid " + callingUid);
        }
        return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
                null, stable, userId);
    }

主要实现在getContentProviderImpl方法中

总体逻辑
  • mProviderMap中不存在该content provider record 或provider对应进程dead

– 该provider为只在system 用户空间存在的单例

— 没有异常则创建新的content provider record

— 判断mLaunchingProviders是否有当前provider

---- 没有则先看下是否已有provider对应的进程存在

----- 进程存在,但是对应的provider未发布,则通知app publish 该provider,后面也会设置connection的waiting为true

----- 进程不存在,则先去创建进程;将当前provider添加到mLaunchingProviders

----- 创建connection,设置connection的waiting为true

----- 等待对端publish provider的超时时间为20s

----- 直接返回新建的holder

返回null的情况
  • provider不在运行中且pms解析provider失败
  • provider所在user不在运行中
  • requestTargetProviderPermissionsReviewIfNeededLocked
  • pms解析provider所在application info失败,返回null
  • 进程为bad,创建进程失败
  • provider的binder对象provider不存在且launchingApp为null
抛出异常的情况
  • system server未ready情况,provider不是system进程持有
  • 系统provider未安装情况下,访问的是system进程的provider
    private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
            String name, IBinder token, int callingUid, String callingPackage, String callingTag,
            boolean stable, int userId) {
        ContentProviderRecord cpr;
        ContentProviderConnection conn = null;
        ProviderInfo cpi = null;
        boolean providerRunning = false;
        final int expectedUserId = userId;
        synchronized (mService) {
            long startTime = SystemClock.uptimeMillis();
			// 对caller判断
            ProcessRecord r = null;
            if (caller != null) {
                r = mService.getRecordForAppLOSP(caller);
                if (r == null) {
                    throw new SecurityException("Unable to find app for caller " + caller
                            + " (pid=" + Binder.getCallingPid() + ") when getting content provider "
                            + name);
                }
            }

            boolean checkCrossUser = true;

            checkTime(startTime, "getContentProviderImpl: getProviderByName");

            // 检查mProviderMap中该provider是不是已经发布了
            cpr = mProviderMap.getProviderByName(name, userId);
            // 如果当前查询的user不是system,且要查找的provider是只能存在system的单例
            if (cpr == null && userId != UserHandle.USER_SYSTEM) {
                cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
                if (cpr != null) {
                    cpi = cpr.info;
                    if (mService.isSingleton(
                            cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags)
                            && mService.isValidSingletonCall(
                           r == null ? callingUid : r.uid, cpi.applicationInfo.uid)) {
						// 将当前的userId改成system
                        userId = UserHandle.USER_SYSTEM;
						// 校验user的标识置为false
                        checkCrossUser = false;
                    } else {
						// 如果不是单例,重新置provider等为null
                        cpr = null;
                        cpi = null;
                    }
                }
            }

            ProcessRecord dyingProc = null;
            if (cpr != null && cpr.proc != null) {
				// 判断当前provider是不是已经在运行了
                providerRunning = !cpr.proc.isKilled();

                // 如果provider所在进程被AMS查杀了,但是没有回调appDiedLocked方法,标记为dyingProc
                if (cpr.proc.isKilled() && cpr.proc.isKilledByAm()) {
                    Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead");
                    // Now we are going to wait for the death before starting the new process.
                    dyingProc = cpr.proc;
                }
            }
			// 当前provider正在运行
            if (providerRunning) {
                cpi = cpr.info;
				// canRunHere主要针对自己请求的provider运行在自己进程中的情况
                if (r != null && cpr.canRunHere(r)) {
                    checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
                            cpr.name.flattenToShortString(), startTime);

                   // 这种情况,无须制造一个connection,且local为true
                    ContentProviderHolder holder = cpr.newHolder(null, true);
                    // don't give caller the provider object, it needs to make its own.
                    holder.provider = null;
                    return holder;
                }

                // Don't expose providers between normal apps and instant apps
                try {
                    if (AppGlobals.getPackageManager()
                            .resolveContentProvider(name, /*flags=*/ 0, userId) == null) {
                        return null;
                    }
                } catch (RemoteException e) {
                }

                checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
                        cpr.name.flattenToShortString(), startTime);
				// 清除caling相关信息,以免校验callingUid等问题
                final long origId = Binder.clearCallingIdentity();
                try {
                    checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");

                    // 建立provider之间的链接.
                    conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage,
                            callingTag, stable, true, startTime, mService.mProcessList,
                            expectedUserId);

                    checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
                    final int verifiedAdj = cpr.proc.mState.getVerifiedAdj();
					// 更新进程优先级
                    boolean success = mService.updateOomAdjLocked(cpr.proc,
                            OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
                    // 如果verify adj和计算后的adj不相等且provider的持有进程死亡
                    if (success && verifiedAdj != cpr.proc.mState.getSetAdj()
                            && !isProcessAliveLocked(cpr.proc)) {
                        success = false;
                    }
                    maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
                    checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
                    // 如果更新adj失败(持有provider的进程死亡等)
                    if (!success) {
                       //打印异常log
                        Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
                                + " is crashing; detaching " + r);
                        boolean lastRef = decProviderCountLocked(conn, cpr, token, stable,
                                false, false);
                        if (!lastRef) {
                            // This wasn't the last ref our process had on
                            // the provider...  we will be killed during cleaning up, bail.
                            return null;
                        }
                        // We'll just start a new process to host the content provider
                        providerRunning = false;
                        conn = null;
                        dyingProc = cpr.proc;
                    } else {
						// provider对应进程存在,设置当前adj为erify adj
                        cpr.proc.mState.setVerifiedAdj(cpr.proc.mState.getSetAdj());
                    }
                } finally {
					// 恢复calling相关信息
                    Binder.restoreCallingIdentity(origId);
                }
            }
			// 进程不存在
            if (!providerRunning) {
                try {
					// 获取provider的info信息
                    checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
                    cpi = AppGlobals.getPackageManager().resolveContentProvider(name,
                            ActivityManagerService.STOCK_PM_FLAGS
                                    | PackageManager.GET_URI_PERMISSION_PATTERNS,
                            userId);
                    checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
                } catch (RemoteException ex) {
                }
				// 获取失败,直接返回null
                if (cpi == null) {
                    return null;
                }
                // 跟上面一次的判读一样
                boolean singleton = mService.isSingleton(
                        cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags)
                            && mService.isValidSingletonCall(
                                    r == null ? callingUid : r.uid, cpi.applicationInfo.uid);
                // 一样
                if (singleton) {
                    userId = UserHandle.USER_SYSTEM;
                }
                cpi.applicationInfo = mService.getAppInfoForUser(cpi.applicationInfo, userId);
                checkTime(startTime, "getContentProviderImpl: got app info for user");

                checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, !singleton,
                        name, startTime);
				// 系统还没ready,抛出异常
                if (!mService.mProcessesReady && !cpi.processName.equals("system")) {
                    throw new IllegalArgumentException(
                            "Attempt to launch content provider before system ready");
                }

                // If system providers are not installed yet we aggressively crash to avoid
                // creating multiple instance of these providers and then bad things happen!
                synchronized (this) {
                    if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
                            && "system".equals(cpi.processName)) {
                        throw new IllegalStateException("Cannot access system provider: '"
                                + cpi.authority + "' before system providers are installed!");
                    }
                }

                // user未运行,返回null
                if (!mService.mUserController.isUserRunning(userId, 0)) {
                    Slog.w(TAG, "Unable to launch app "
                            + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
                            + " for provider " + name + ": user " + userId + " is stopped");
                    return null;
                }
				// 构造component
                ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
                checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
				// 检查AMS这边是否有保存该provider
                cpr = mProviderMap.getProviderByClass(comp, userId);
                checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
                boolean firstClass = cpr == null;
				// 第一次创建
                if (firstClass) {
                    final long ident = Binder.clearCallingIdentity();

                    // If permissions need a review before any of the app components can run,
                    // we return no provider and launch a review activity if the calling app
                    // is in the foreground.
                    if (!requestTargetProviderPermissionsReviewIfNeededLocked(
                            cpi, r, userId, mService.mContext)) {
                        return null;
                    }

                    try {
                        checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
						// 获取provider相关的application信息
                        ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
                                cpi.applicationInfo.packageName,
                                ActivityManagerService.STOCK_PM_FLAGS, userId);
                        checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
                        if (ai == null) {
                            Slog.w(TAG, "No package info for content provider " + cpi.name);
                            return null;
                        }
						// 构造新的content provider对象
                        ai = mService.getAppInfoForUser(ai, userId);
                        cpr = new ContentProviderRecord(mService, cpi, ai, comp, singleton);
                    } catch (RemoteException ex) {
                        // pm is in same process, this will never happen.
                    } finally {
                        Binder.restoreCallingIdentity(ident);
                    }
                } else if (dyingProc == cpr.proc && dyingProc != null) {
                    // The old stable connection's client should be killed during proc cleaning up,
                    // so do not re-use the old ContentProviderRecord, otherwise the new clients
                    // could get killed unexpectedly.
                    cpr = new ContentProviderRecord(cpr);
                    // This is sort of "firstClass"
                    firstClass = true;
                }

                checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");

                if (r != null && cpr.canRunHere(r)) {
                    // 上面一样的逻辑
                    return cpr.newHolder(null, true);
                }

                // 看看当前请求的provider是不是在mLaunchingProviders
				// 如果一个 provider被请求过,但是因为对方进程没有启动没有publishProvider
				// 则会加入mLaunchingProviders中
                final int numLaunchingProviders = mLaunchingProviders.size();
                int i;
                for (i = 0; i < numLaunchingProviders; i++) {
                    if (mLaunchingProviders.get(i) == cpr) {
                        break;
                    }
                }

                // 没有正在启动该provider进程
                if (i >= numLaunchingProviders) {
                    final long origId = Binder.clearCallingIdentity();

                    try {
                      .....
                        // Content provider is now in use, its package can't be stopped.
                        try {
                            checkTime(startTime,
                                    "getContentProviderImpl: before set stopped state");
                            AppGlobals.getPackageManager().setPackageStoppedState(
                                    cpr.appInfo.packageName, false, userId);
                            checkTime(startTime, "getContentProviderImpl: after set stopped state");
                        } catch (RemoteException e) {
                        } catch (IllegalArgumentException e) {
                            Slog.w(TAG, "Failed trying to unstop package "
                                    + cpr.appInfo.packageName + ": " + e);
                        }

                        // Use existing process if already started
                        checkTime(startTime, "getContentProviderImpl: looking for process record");
						// 进程已经存在
                        ProcessRecord proc = mService.getProcessRecordLocked(
                                cpi.processName, cpr.appInfo.uid);
                        IApplicationThread thread;
                        if (proc != null && (thread = proc.getThread()) != null
                                && !proc.isKilled()) {
                           // 进程存在,但是没有对应的provider,则通知app端install provider
                            final ProcessProviderRecord pr = proc.mProviders;
                            if (!pr.hasProvider(cpi.name)) {
                                checkTime(startTime, "getContentProviderImpl: scheduling install");
                                pr.installProvider(cpi.name, cpr);
                                try {
                                    thread.scheduleInstallProvider(cpi);
                                } catch (RemoteException e) {
                                }
                            }
                        } else {
							// 进程不存在,启动进程
                            checkTime(startTime, "getContentProviderImpl: before start process");
                            proc = mService.startProcessLocked(
                                    cpi.processName, cpr.appInfo, false, 0,
                                    new HostingRecord("content provider",
                                        new ComponentName(
                                                cpi.applicationInfo.packageName, cpi.name)),
                                    Process.ZYGOTE_POLICY_FLAG_EMPTY, false, false);
                            checkTime(startTime, "getContentProviderImpl: after start process");
							// 短时间内crash多次,启动失败,打印异常log
                            if (proc == null) {
                                Slog.w(TAG, "Unable to launch app "
                                        + cpi.applicationInfo.packageName + "/"
                                        + cpi.applicationInfo.uid + " for provider " + name
                                        + ": process is bad");
                                return null;
                            }
                        }
                        cpr.launchingApp = proc;
						// 将当前provider加到laucnhing列表,避免二次创建进程
                        mLaunchingProviders.add(cpr);
                    } finally {
                        Binder.restoreCallingIdentity(origId);
                    }
                }

                checkTime(startTime, "getContentProviderImpl: updating data structures");

               	// 第一次创建,将当前provider加入mProviderMap map中
                if (firstClass) {
                    mProviderMap.putProviderByClass(comp, cpr);
                }
				// 根据name加入map中
                mProviderMap.putProviderByName(name, cpr);
				// 创建连接
                conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
                        stable, false, startTime, mService.mProcessList, expectedUserId);
				// 等待对端publish provider
                if (conn != null) {
                    conn.waiting = true;
                }
            }
            checkTime(startTime, "getContentProviderImpl: done!");

            mService.grantImplicitAccess(userId, null, callingUid,
                    UserHandle.getAppId(cpi.applicationInfo.uid));

            if (caller != null) {
                // The client will be waiting, and we'll notify it when the provider is ready.
                synchronized (cpr) {
                    if (cpr.provider == null) {
                        if (cpr.launchingApp == null) {
                            Slog.w(TAG, "Unable to launch app "
                                    + cpi.applicationInfo.packageName + "/"
                                    + cpi.applicationInfo.uid + " for provider "
                                    + name + ": launching app became null");
                            EventLogTags.writeAmProviderLostProcess(
                                    UserHandle.getUserId(cpi.applicationInfo.uid),
                                    cpi.applicationInfo.packageName,
                                    cpi.applicationInfo.uid, name);
                            return null;
                        }

                        if (conn != null) {
                            conn.waiting = true;
                        }
                        Message msg = mService.mHandler.obtainMessage(
                                ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG);
                        msg.obj = cpr;
                        mService.mHandler.sendMessageDelayed(msg,
                                ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
                    }
                }
                // Return a holder instance even if we are waiting for the publishing of the
                // provider, client will check for the holder.provider to see if it needs to wait
                // for it.
				// 返回holder
                return cpr.newHolder(conn, false);
            }
        }

        // Because of the provider's external client (i.e., SHELL), we'll have to wait right here.
        // Wait for the provider to be published...
        final long timeout =
                SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
        boolean timedOut = false;
        synchronized (cpr) {
            while (cpr.provider == null) {
                if (cpr.launchingApp == null) {
                    Slog.w(TAG, "Unable to launch app "
                            + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
                            + " for provider " + name + ": launching app became null");
                    EventLogTags.writeAmProviderLostProcess(
                            UserHandle.getUserId(cpi.applicationInfo.uid),
                            cpi.applicationInfo.packageName, cpi.applicationInfo.uid, name);
                    return null;
                }
                try {
                    final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
                    if (DEBUG_MU) {
                        Slog.v(TAG_MU, "Waiting to start provider " + cpr
                                + " launchingApp=" + cpr.launchingApp + " for " + wait + " ms");
                    }
                    if (conn != null) {
                        conn.waiting = true;
                    }
                    cpr.wait(wait);
                    if (cpr.provider == null) {
                        timedOut = true;
                        break;
                    }
                } catch (InterruptedException ex) {
                } finally {
                    if (conn != null) {
                        conn.waiting = false;
                    }
                }
            }
        }
        if (timedOut) {
            // Note we do it after releasing the lock.
            String callerName = "unknown";
            if (caller != null) {
                synchronized (mService.mProcLock) {
                    final ProcessRecord record =
                            mService.mProcessList.getLRURecordForAppLOSP(caller);
                    if (record != null) {
                        callerName = record.processName;
                    }
                }
            }

            Slog.wtf(TAG, "Timeout waiting for provider "
                    + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
                    + " for provider " + name + " providerRunning=" + providerRunning
                    + " caller=" + callerName + "/" + Binder.getCallingUid());
            return null;
        }
        return cpr.newHolder(conn, false);
    }

    @GuardedBy("mService")
    private ContentProviderConnection incProviderCountLocked(ProcessRecord r,
            final ContentProviderRecord cpr, IBinder externalProcessToken, int callingUid,
            String callingPackage, String callingTag, boolean stable, boolean updateLru,
            long startTime, ProcessList processList, @UserIdInt int expectedUserId) {
        if (r == null) {
            cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
            return null;
        }

		// 获取caller进程的所有content provider的信息
        final ProcessProviderRecord pr = r.mProviders;
        for (int i = 0, size = pr.numberOfProviderConnections(); i < size; i++) {
            ContentProviderConnection conn = pr.getProviderConnectionAt(i);
			// 如果当前要获取的provider在该caller进程中已有相关连接,则计数+1
            if (conn.provider == cpr) {
                conn.incrementCount(stable);
				// 获取链接直接返回
                return conn;
            }
        }

        // 新建一个content provider的连接
        ContentProviderConnection conn = new ContentProviderConnection(cpr, r, callingPackage,
                expectedUserId);
        conn.startAssociationIfNeeded();
		// 初始化count为1
        conn.initializeCount(stable);
		// 将当前连接添加到conten provider的连接列表里
        cpr.connections.add(conn);
		// 将当前链接保存到进程provider列表里
        pr.addProviderConnection(conn);
        mService.startAssociationLocked(r.uid, r.processName, r.mState.getCurProcState(),
                cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
        if (updateLru && cpr.proc != null
                && r.mState.getSetAdj() <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
            // caller的adj <= 250,更新持有provider进程的adj
            checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
            processList.updateLruProcessLocked(cpr.proc, false, null);
            checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
        }
        return conn;
    }

ContentProvider的三千问

  1. ContentProviderConnection 会被哪些类持有引用?ProcessProviderRecord、ContentProviderRecord
  2. 持有provider的进程死亡如何处理?
  3. 获取到的provider返回null的情况有哪些?抛出异常的情况有哪些?

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值