Android Content Provider的启动过程源码分析

本文參考Android应用程序组件Content Provider的启动过程源码分析http://blog.csdn.net/luoshengyang/article/details/6963418和《Android系统源码情景分析》,作者罗升阳。

0、总图流程图例如以下:

Android Content Provider的启动过程源码分析

1、MainActivity进程向ActivityServiceManager主线程发送GET_CONTENT_PORVIDER_TRANSACTION

例如以下图:

Android Content Provider的启动过程源码分析

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamx0eGdjeQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

如图:第一步

~/Android/frameworks/base/core/java/android/app

----ActivityManagerNative.java

class ActivityManagerProxy implements IActivityManager
{
...... public ContentProviderHolder getContentProvider(IApplicationThread caller,
String name) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(name);
mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
ContentProviderHolder cph = null;
if (res != 0) {
cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
}
data.recycle();
reply.recycle();
return cph;
} ......
}

当中name为shy.luo.providers.articles。

如图:第二步,省略binder_transaction传输过程,由于上面已经分析过了。

如图:第三步

~/Android/frameworks/base/core/java/android/app

----ActivityManagerNative.java

public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
......
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case GET_CONTENT_PROVIDER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String name = data.readString();
ContentProviderHolder cph = getContentProvider(app, name);
reply.writeNoException();
if (cph != null) {
reply.writeInt(1);
cph.writeToParcel(reply, 0);
} else {
reply.writeInt(0);
}
return true;
} .......
}

当中name为shy.luo.providers.articles。

如图:第四步

~/Android/frameworks/base/services/java/com/android/server/am

----ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...... public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name) {
...... return getContentProviderImpl(caller, name);
} ......
}

它调用getContentProviderImpl函数来进一步运行操作。

public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...... private final ContentProviderHolder getContentProviderImpl(
IApplicationThread caller, String name) {
ContentProviderRecord cpr;
ProviderInfo cpi = null; synchronized(this) {
ProcessRecord r = null;
if (caller != null) {
r = getRecordForAppLocked(caller);
......
} // First check if this content provider has been published...
cpr = mProvidersByName.get(name);
if (cpr != null) {
......
} else {
try {
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} catch (RemoteException ex) {
}
......
} cpr = mProvidersByClass.get(cpi.name);
final boolean firstClass = cpr == null;
if (firstClass) {
try {
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS);
......
cpr = new ContentProviderRecord(cpi, ai);
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
}
} if (r != null && cpr.canRunHere(r)) {
// If this is a multiprocess provider, then just return its
// info and allow the caller to instantiate it. Only do
// this if the provider is the same user as the caller's
// process, or can run as root (so can be in any process).
return cpr;
} ...... // This is single process, and our app is now connecting to it.
// See if we are already in the process of launching this
// provider.
final int N = mLaunchingProviders.size();
int i;
for (i=0; i<N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
} // If the provider is not already being launched, then get it
// started.
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
ProcessRecord proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false);
......
mLaunchingProviders.add(cpr);
......
} // Make sure the provider is published (the same provider class
// may be published under multiple names).
if (firstClass) {
mProvidersByClass.put(cpi.name, cpr);
}
cpr.launchingApp = proc;
mProvidersByName.put(name, cpr); ......
} // Wait for the provider to be published...
synchronized (cpr) {
while (cpr.provider == null) {
......
try {
cpr.wait();
} catch (InterruptedException ex) {
}
}
} return cpr;
} ......
}

主要做了下面几件事:

(1)依据传递过来的name创建了ProviderInfo对象和ApplicationInfo对象,然后依据它们两个对象创建了ContentProviderRecord对象。

(2)创建了ProcessRecord对象,并创建ArticlesProvider子线程。

(3)循环等待cpr.provider的值不为null。

2、创建ArticlesProvider子线程,略。

3、ArticlesProvider子线程向ActivityManagerService子线程发送ATTACH_APPLICATION_TRANSACTION

第一、二、三步所有省略。仅仅看第四步。

~/Android/frameworks/base/services/java/com/android/server/am

----ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...... private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else if (mStartingProcesses.size() > 0) {
......
} else {
......
} ...... app.thread = thread;
app.curAdj = app.setAdj = -100;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.forcingToForeground = null;
app.foregroundServices = false;
app.debugging = false; ...... boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List providers = normalMode ? generateApplicationProvidersLocked(app) : null; try {
...... thread.bindApplication(processName, app.instrumentationInfo != null
? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode || !normalMode,
mConfiguration, getCommonServicesLocked()); ......
} catch (Exception e) {
......
} ...... return true;
} ...... private final List generateApplicationProvidersLocked(ProcessRecord app) {
List providers = null;
try {
providers = AppGlobals.getPackageManager().
queryContentProviders(app.processName, app.info.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} catch (RemoteException ex) {
}
if (providers != null) {
final int N = providers.size();
for (int i=0; i<N; i++) {
ProviderInfo cpi =
(ProviderInfo)providers.get(i);
ContentProviderRecord cpr = mProvidersByClass.get(cpi.name);
if (cpr == null) {
cpr = new ContentProviderRecord(cpi, app.info);
mProvidersByClass.put(cpi.name, cpr);
}
app.pubProviders.put(cpi.name, cpr);
app.addPackage(cpi.applicationInfo.packageName);
ensurePackageDexOpt(cpi.applicationInfo.packageName);
}
}
return providers;
} ......
}

主要做了下面几件事:

(1)获取了刚在ActivityServiceManager主线程创建的ProcessRecord对象。

(2)依据这个ProcessRecord对象获得刚在ActivityServiceManager主线程中的ProviderInfo对象。

(3)ActivityServiceManager子线程向ArticlesProvider子线程发送BIND_APPLICATION_TRANSACTION。

4、ActivityServiceManager子线程向ArticlesProvider子线程发送BIND_APPLICATION_TRANSACTION

Android Content Provider的启动过程源码分析

如图:第一步

~/Android/frameworks/base/core/java/android/app

----ApplicationThreadNative.java。ApplicationThreadProxy类

    public final void bindApplication(String packageName, ApplicationInfo info,
List<ProviderInfo> providers, ComponentName testName,
String profileName, Bundle testArgs, IInstrumentationWatcher testWatcher, int debugMode,
boolean restrictedBackupMode, Configuration config,
Map<String, IBinder> services) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeString(packageName);
info.writeToParcel(data, 0);
data.writeTypedList(providers);
if (testName == null) {
data.writeInt(0);
} else {
data.writeInt(1);
testName.writeToParcel(data, 0);
}
data.writeString(profileName);
data.writeBundle(testArgs);
data.writeStrongInterface(testWatcher);
data.writeInt(debugMode);
data.writeInt(restrictedBackupMode ? 1 : 0);
config.writeToParcel(data, 0);
data.writeMap(services);
mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}

当中providers是在ActivityServiceManager主线程依据传递过来的name创建了ProviderInfo对象。

如图:第二步,省略binder_transaction传输过程,由于上面已经分析过了。

如图:第三步

~/Android/frameworks/base/core/java/android/app

----ApplicationThreadNative.java

public abstract class ApplicationThreadNative extends Binder
implements IApplicationThread {
........
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case BIND_APPLICATION_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
String packageName = data.readString();
ApplicationInfo info =
ApplicationInfo.CREATOR.createFromParcel(data);
List<ProviderInfo> providers =
data.createTypedArrayList(ProviderInfo.CREATOR);
ComponentName testName = (data.readInt() != 0)
? new ComponentName(data) : null;
String profileName = data.readString();
Bundle testArgs = data.readBundle();
IBinder binder = data.readStrongBinder();
IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder);
int testMode = data.readInt();
boolean restrictedBackupMode = (data.readInt() != 0);
Configuration config = Configuration.CREATOR.createFromParcel(data);
HashMap<String, IBinder> services = data.readHashMap(null);
bindApplication(packageName, info,
providers, testName, profileName,
testArgs, testWatcher, testMode, restrictedBackupMode,
config, services);
return true;
}
.....
}

当中providers是在ActivityServiceManager主线程依据传递过来的name创建了ProviderInfo对象。

如图:第四步

~/Android/frameworks/base/core/java/android/app

----ActivityThread.java

public final class ActivityThread {
...... private final class ApplicationThread extends ApplicationThreadNative {
...... public final void bindApplication(String processName,
ApplicationInfo appInfo, List<ProviderInfo> providers,
ComponentName instrumentationName, String profileFile,
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
int debugMode, boolean isRestrictedBackupMode, Configuration config,
Map<String, IBinder> services) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
} AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.profileFile = profileFile;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.debugMode = debugMode;
data.restrictedBackupMode = isRestrictedBackupMode;
data.config = config;
queueOrSendMessage(H.BIND_APPLICATION, data);
} ......
} ......
}

这个函数把相关的信息都封装成一个AppBindData对象,然后以一个消息的形式发送到主线程的消息队列中去等等待处理。这个消息终于在ArticlesProvider主线程中处理。

5、ArticlesProvider主线程installContentProvider

      主要做了下面几件事:

(1)依据传递过来的providers把ArticlesProvider这个Content Provider类载入到内存中来了,并调用了它的onCreat方法。

(2)创建了Transport对象,它的关系图例如以下:

Android Content Provider的启动过程源码分析

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamx0eGdjeQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

  (3)ArticlesProvider主线程ActivityServiceManager子线程发送PUBLISH_CONTENT_PROVIDER_TRANSACTION

6、ArticlesProvider主线程ActivityServiceManager子线程发送PUBLISH_CONTENT_PROVIDER_TRANSACTION

第一、二、三步所有省略。仅仅看第四步。

~/Android/frameworks/base/services/java/com/android/server/am

----ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...... public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
...... synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
...... 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 (dst != null) {
mProvidersByClass.put(dst.info.name, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
mProvidersByName.put(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.app = r;
dst.notifyAll();
}
......
}
}
}
} ......
}

还记得ActivityServiceManager在循环等待么?这里dst.provider = src.provider,为ContentProviderProxy对象(实现了IContentProvider)。

之后调用notifyAll通知ActivityManagerService主线程,让它从等待中返回。

7、notifyAll通知ActivityManagerService主线程

8、ActivityManagerService主线程向MainActivity进程发送返回结果

~/Android/frameworks/base/core/java/android/app

----ActivityThread.java

	private final IContentProvider getProvider(Context context, String name) {
IContentProvider existing = getExistingProvider(context, name);
if (existing != null) {
return existing;
} IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), name);
} catch (RemoteException ex) {
} IContentProvider prov = installProvider(context, holder.provider,
holder.info, true); ...... return prov;
}
public class ArticlesAdapter {
...... private ContentResolver resolver = null; public ArticlesAdapter(Context context) {
resolver = context.getContentResolver();
} ...... public int getArticleCount() {
int count = 0; try {
IContentProvider provider = resolver.acquireProvider(Articles.CONTENT_URI);
Bundle bundle = provider.call(Articles.METHOD_GET_ITEM_COUNT, null, null);
count = bundle.getInt(Articles.KEY_ITEM_COUNT, 0);
} catch(RemoteException e) {
e.printStackTrace();
} return count;
} ......
}

最后返回的是ContentProviderProxy对象,指向了ArticlesProvider主线程中Transport对象。例如以下图:

Android Content Provider的启动过程源码分析

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamx0eGdjeQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" style="font-size:14px">

Bundle bundle = provider.call(Articles.METHOD_GET_ITEM_COUNT, null, null);

使用进程间通信的方式取得博客栏目数量。

由于要传输的数据比較小。

上一篇:Android Activity启动流程源码全解析(2)


下一篇:最新版jQuery v3.3.1的BUG以及解决办法(什么问题不重要,怎么解决问题才重要)