基础知识
基于Android 12.0
一些概念
framework层ContentProvider相关逻辑主要在AMS类中(android 12.0+在ContentProviderHelper中),代表一个provider的是ContentProviderRecord
- ContentProvider通过uri来标识其他应用要访问的数据,通过ContentResolver的增、删、改、查来实现对共享数据的操作,通过注册ContentObserver来监听数据的变化。
- ContentProvider是一个抽象类,主要有onCreate()、query()、insert()、delete()、update()、getType()等方法。
- ContentProvider对底层的数据存储方式没有任何要求,可以是sqlite、xml文件、表格等。
常用命令
- 查询:adb shell content query --uri content://settings/settings
- 查看系统所有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中的逻辑如下:
- 存在直接获取
- 可以直接通过AMS查询到
- 等待对端provider发布成功,超时20s
- 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的三千问
- ContentProviderConnection 会被哪些类持有引用?ProcessProviderRecord、ContentProviderRecord
- 持有provider的进程死亡如何处理?
- 获取到的provider返回null的情况有哪些?抛出异常的情况有哪些?