Android筑基——ContentProvider 的跨进程启动过程和数据 *** 作方法调用过程(基于api21)

Android筑基——ContentProvider 的跨进程启动过程和数据 *** 作方法调用过程(基于api21),第1张

Android筑基——ContentProvider 的跨进程启动过程和数据 *** 作方法调用过程(基于api21)

目录
  • 1.前言
  • 2.正文
    • 2.1 小例子
    • 2.2 代码分析
      • 2.2.1 ContextWrapper.getContentResolver() 方法
      • 2.2.2 ContextImpl.getContentResolver() 方法
      • 2.2.3 ContentResolver.query() 方法
      • 2.2.4 ContentResolver.acquireUnstableProvider() 方法
      • 2.2.5 ApplicationContentResolver.acquireUnstableProvider() 方法
      • 2.2.6 ActivityThread.acquireProvider() 方法
        • 2.2.6.1 ActivityThread.acquireExistingProvider() 方法
        • 2.2.6.2 ActivityManagerNative.getDefault() 方法
      • 2.2.7 ActivityManagerProxy.getContentProvider() 方法
      • 2.2.8 ActivityManagerNative.onTransact() 方法
      • 2.2.9 ActivityManagerService.getContentProvider() 方法
      • 2.2.10 ActivityManagerService.getContentProviderImpl() 方法
        • 2.2.10.1 ProviderMap 类
        • 2.2.10.2 ContentProviderRecord.canRunHere() 方法
      • 2.2.11 ActivityManagerService.startProcessLocked() 方法
        • 2.2.11.1 ActivityManagerService.newProcessRecordLocked() 方法
      • 2.2.12 ActivityManagerService.startProcessLocked() 方法
      • 2.2.13 Process.start() 方法
      • 2.2.14 ActivityThread.main() 方法
      • 2.2.15 ActivityThread.attach() 方法
      • 2.2.16 ActivityManagerService.attachApplication() 方法
      • 2.2.17 ActivityManagerService.attachApplicationLocked() 方法
        • 2.2.17.1 ActivityManagerService.generateApplicationProvidersLocked() 方法
      • 2.2.18 ApplicationThreadProxy.bindApplication() 方法
      • 2.2.19 ApplicationThreadNative.onTransact() 方法
      • 2.2.20 ApplicationThread.bindApplication() 方法
      • 2.2.21 H.handleMessage() 方法
      • 2.2.22 ActivityThread.handleBindApplication() 方法
      • 2.2.23 ActivityThread.installContentProviders() 方法
      • 2.2.24 ActivityThread.installProvider() 方法
        • 2.2.24.1 ContentProvider.attachInfo() 方法
        • 2.2.24.2 ActivityThread.installProviderAuthoritiesLocked() 方法
      • 2.2.25 ActivityManagerService.publishContentProviders() 方法
      • 2.2.26 ActivityManagerService.getContentProviderImpl() 方法跳出循环等待 provider 发布
      • 2.2.27 ActivityThread.acquireProvider() 方法
        • 2.2.27.1 ActivityThread.installProvider() 方法
        • 2.2.27.2 ActivityThread.installProviderAuthoritiesLocked() 方法
      • 2.2.28 ContentProviderProxy.query() 方法
      • 2.2.29 ContentProviderNative.onTransact() 方法
      • 2.2.30 Transport.query() 方法
      • 2.2.31 BookProvider.query() 方法
  • 3.最后
  • 4.参考

1.前言

ContentProvider (内容提供者)是 Android 的四大组件之一,是一种内容共享型组件,它提供了数据的统一访问格式,通过单一的 ContentResolver 接口把数据提供给其他应用。只有在多个应用之间分享数据时,ContentProvider 才是必须的。

由 ContentResolver 接口发起的insert(增加)、delete(删除)、update(更新)、query(查询)数据 *** 作会发给 ContentProvider 对应的 insert(增加)、delete(删除)、update(更新)、query(查询)方法。

我们一般认为,内容提供者的数据来源是数据库,但实际上,内容提供者对底层的数据存储方式没有任何要求,可以使用数据库,也可以使用普通的文件,也可以使用内存中的一个对象,还可以使用网络数据。

换句话说,ContentProvider 提供了一种抽象,隔离了数据的使用方和数据的提供方,这样即便数据的提供方修改了数据存储实现,也不会影响到依赖数据访问的其他现有应用(即数据的使用方),具体而言,内容提供者使用数据库作为数据来源,当它把数据来源更改为 SharedPreferences 时,数据的使用方是不会受到影响的,数据的使用方是感知不到的。

在实际开发中,我们使用别人提供的内容提供者的时候比较多,比如使用 Android 系统中自带的电话簿(ContactsContract)获取联系人列表,使用 Android 系统中自带的 MediaStore(媒体库)获取媒体信息(如 MediaStore.Audio 音频数据,MediaStore.Video 视频数据,MediaStore.Files 文件数据,MediaStore.Images 图片数据)。Android 框架实现的部分内容提供程序位于 android.provider 包下。

而自己开发内容提供者给别人用比较少,一个应用是使用 ContentProvider 在 library 里直接获取上下文,不必再由主工程传递上下文给 library 了(不过,谷歌不推荐这样做)。

本文主要包括:

  • 演示一个使用了 ContentProvider 的小例子,这也是我们本次要分析的场景;
  • ContentProvider 的跨进程启动过程,这样我们就可以知道为什么 ContentProvider 的 onCreate() 方法要先于 Application 的 onCreate() 方法执行;
  • ContentProvider 的数据 *** 作方法调用过程,这里以 query(查询)方法为例来说明,这样可以知道由 ContentResolver 的 query 方法发起的查询 *** 作如何最终交由 ContentProvider 的 query 方法来执行。
2.正文 2.1 小例子

例子部分请查看BookProvider。

本文不打算讲解这个例子了,因为本文已经很长了。

这里说明一下分析的场景:BookProvider 位于一个单独的进程里面;在客户端调用 ContentResolver 的 query 方法时,BookProvider 所处的进程还未启动,因此需要先开启目标进程。

2.2 代码分析 2.2.1 ContextWrapper.getContentResolver() 方法
@Override
public ContentResolver getContentResolver() {
    return mbase.getContentResolver();
}

这里的 ContextWrapper其实是装饰器设计模式的应用了,类结构图如下所示:

调用装饰类 ContextWrapper 的 getContentResolver()方法,内部真正调用的是核心实现类 ContextImpl 的 getContentResolver()方法。所以 mbase 实际上是一个 ContextImpl 类型的对象。

2.2.2 ContextImpl.getContentResolver() 方法
class ContextImpl extends Context {
	private final ApplicationContentResolver mContentResolver;
	
	private ContextImpl(ContextImpl container, ActivityThread mainThread,
			LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
			Display display, Configuration overrideConfiguration) {
		...
		// 初始化 ApplicationContentResolver 对象。
		mContentResolver = new ApplicationContentResolver(this, mainThread, user);
	}
	
	@Override
	public ContentResolver getContentResolver() {
		return mContentResolver;
	}
	private static final class ApplicationContentResolver extends ContentResolver {
		private final ActivityThread mMainThread;
		private final UserHandle mUser;
		public ApplicationContentResolver(
				Context context, ActivityThread mainThread, UserHandle user) {
			super(context);
			mMainThread = Preconditions.checkNotNull(mainThread);
			mUser = Preconditions.checkNotNull(user);
		}
		@Override
		protected IContentProvider acquireProvider(Context context, String auth) {
			return mMainThread.acquireProvider(context,
					ContentProvider.getAuthorityWithoutUserId(auth),
					resolveUserIdFromAuthority(auth), true);
		}
		... // 省略一些重写的方法
	}
}

可以看到,最终返回的是一个 mContentResolver 对象,它的类型是 ApplicationContentResolver,它是在 ContextImpl 的构造方法中被初始化的。

在初始化ApplicationContentResolver对象时,传入了 ActivityThread 对象,并且 ApplicationContentResolver 对象内部持有了 ActivityThread 对象。

ApplicationContentResolver是继承于 ContentResolver 抽象类的具体类,它是 ContextImpl 的私有嵌套内部类。

让我们用 UML 图来表示它们之间的关系:

可以看到,ApplicationContentResolver 实现了基类 ContentResolver 的一系列 acquireXXX 以及 releaseXXX 的方法,而方法内部的实现则是委托给 ActivityThread 对象的相应方法来完成。

2.2.3 ContentResolver.query() 方法
  • Uri uri, Uri.parse(“content://com.wzc.chapter_9.bookprovider/books”)
  • String[] projection, null
  • String selection, null
  • String[] selectionArgs, null
  • String sortOrder, null
public final Cursor query(Uri uri, String[] projection,
        String selection, String[] selectionArgs, String sortOrder) {
    return query(uri, projection, selection, selectionArgs, sortOrder, null);
}

调用重载的 query() 方法:

  • Uri uri, Uri.parse(“content://com.wzc.chapter_9.bookprovider/books”)
  • String[] projection, null
  • String selection, null
  • String[] selectionArgs, null
  • String sortOrder, null
  • CancellationSignal cancellationSignal, null
public final Cursor query(final Uri uri, String[] projection,
        String selection, String[] selectionArgs, String sortOrder,
        CancellationSignal cancellationSignal) {
	// 获取 IContentProvider 对象,见【2.2.4】。
    IContentProvider unstableProvider = acquireUnstableProvider(uri);
    if (unstableProvider == null) {
        return null;
    }
    Cursor qCursor = null;
    try {
        ICancellationSignal remoteCancellationSignal = null;
        if (cancellationSignal != null) { // cancellationSignal 为 null,所以不会进入此分支
			...
        }
        try {
			// 获取 Cursor 对象,见【2.2.28】
            qCursor = unstableProvider.query(mPackageName, uri, projection,
                    selection, selectionArgs, sortOrder, remoteCancellationSignal);
        } catch (DeadObjectException e) {
            // 省略异常的代码部分
        }
        if (qCursor == null) {
            return null;
        }
        qCursor.getCount();
        // 把 Cursor 对象包装成 CursorWrapperInner 对象返回.
        CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, acquireProvider(uri));
        qCursor = null;
        return wrapper;
    } catch (RemoteException e) {
        return null;
    } finally {
        if (qCursor != null) {
            qCursor.close();
        }
        if (unstableProvider != null) {
            releaseUnstableProvider(unstableProvider);
        }
    }
}
2.2.4 ContentResolver.acquireUnstableProvider() 方法
  • Uri uri, Uri.parse(“content://com.wzc.chapter_9.bookprovider/books”)
public static final String SCHEME_ConTENT = "content";
public final IContentProvider acquireUnstableProvider(Uri uri) {
    if (!SCHEME_CONTENT.equals(uri.getScheme())) { // uri.getScheme() 是 "content",不会进入此分支
        return null;
    }
    String auth = uri.getAuthority(); // auth 等于 "com.wzc.chapter_9.bookprovider"
    if (auth != null) { // 进入此分支
        return acquireUnstableProvider(mContext, uri.getAuthority());
    }
    return null;
}

调用重载的 acquireUnstableProvider() 方法:

protected abstract IContentProvider acquireUnstableProvider(Context c, String name);

这是一个抽象方法,它的实现是在 ContextImpl.ApplicationContentResolver 里面。

这里出现了 IContentProvider 接口,这是一个用于跨进程通信的接口。与之相关的 binder 客户端与服务端类 UML 图如下:

比较疑惑的是,这里返回的 IContentProvider 对象到底是个什么对象,是 ContentProviderProxy 对象,还是 ContentProviderNative 对象呢?

我们现在还不得而知,但是我们可以通过Debug:

getContentResolver().acquireUnstableProvider(BookStore.Books.CONTENT_URI);

得到:

很明显,返回的是一个 ContentProviderProxy 对象,也就是说,是一个 binder 客户端对象。

那么,客户端进程就是通过这个 binder 客户端对象,经过 binder 驱动,发起远程调用,从 binder 服务端那里获取到数据的。

而由上面的类图可知,IContentProvider 接口对应的 binder 服务端对象是 ContentProvider 的内部类 Transport。

这样就构成了 binder 跨进程通信的客户端和服务端了。

2.2.5 ApplicationContentResolver.acquireUnstableProvider() 方法
  • Context c, ContextImpl 对象
  • String auth, “com.wzc.chapter_9.bookprovider”
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
    return mMainThread.acquireProvider(c,
            ContentProvider.getAuthorityWithoutUserId(auth),
            resolveUserIdFromAuthority(auth), false);
}

本次的 auth 经过 ContentProvider.getAuthorityWithoutUserId(auth) 后,仍为 "com.wzc.chapter_9.bookprovider"。
resolveUserIdFromAuthority(auth) 的结果是 0。

2.2.6 ActivityThread.acquireProvider() 方法
  • Context c, ContextImpl 对象
  • String auth, “com.wzc.chapter_9.bookprovider”
  • int userId, 0
  • boolean stable, false
public final IContentProvider acquireProvider(
        Context c, String auth, int userId, boolean stable) {
	// 获取已经存在的 IContentProvider 对象,见【2.2.6.1】
    final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
    if (provider != null) { // 本次分析 provider 为 null,所以不会进入此分支了。
		// 如果可以获取到已经存在的 IContentProvider 对象,就直接返回了。
        return provider;
    }
    IActivityManager.ContentProviderHolder holder = null;
    try {
		// 向 AMS 请求获取 ContentProviderHolder 对象
        // ActivityManagerNative.getDefault() 的返回 ActivityManagerProxy 对象,分析见 【2.2.6.2】
        // ActivityManagerProxy.getContentProvider() 分析,见【2.2.7】
        holder = ActivityManagerNative.getDefault().getContenProvider(
                getApplicationThread(), auth, userId, stable)
    } catch (RemoteException ex) {
    }
    if (holder == null) {
        // 如果 AMS 返回的 ContentProviderHolder 对象为 null,则直接返回 null。
        return null;
    }
	// 安装 provider 将会增加引用计数,并且打破竞争中的任何联系。
    holder = installProvider(c, holder, holder.info,
            true , holder.noReleaseNeeded, stable);
    return holder.provider;
}

该方法的主要作用:

  1. 尝试获取已经存在的 IContentProvider 对象;
  2. 如果 1 获取不到 IContentProvider 对象,再向 AMS 请求获取 ContentProviderHolder 对象;
  3. 如果 2 获取的 ContentProviderHolder 对象不为 null,则调用安装 provider 的方法。
2.2.6.1 ActivityThread.acquireExistingProvider() 方法
  • Context c, ContextImpl 对象
  • String auth, “com.wzc.chapter_9.bookprovider”
  • int userId, 0
  • boolean stable, false
// mProviderMap 以 ProviderKey 为键,以 ProviderClientRecord 为值
final ArrayMap mProviderMap
    = new ArrayMap();
	
final ArrayMap mProviderRefCountMap
    = new ArrayMap();
	
public final IContentProvider acquireExistingProvider(
        Context c, String auth, int userId, boolean stable) {
    synchronized (mProviderMap) {
		// 把 auth 和 userId 封装为 ProviderKey 对象。
        final ProviderKey key = new ProviderKey(auth, userId);
		// 从 mProviderMap 查找对应 ProviderKey 的 ProviderClientRecord 对象
        final ProviderClientRecord pr = mProviderMap.get(key);
        if (pr == null) { 
			// 本次分析,获取的 pr 为 null,所以直接在这里返回了。
            return null;
        }
        // ###下面的代码,本次分析不会走到了###。
        IContentProvider provider = pr.mProvider;
        IBinder jBinder = provider.asBinder();
        if (!jBinder.isBinderAlive()) {
			// provider 的宿主进程已经死亡,不能使用这个 binder 了。
            handleUnstableProviderDiedLocked(jBinder, true);
            return null;
        }
		// 如果我们有一个 ProviderRefCount 对象,就仅仅增加引用计数;
		// 否则,说明这个 provider 没有被引用计数,也不需要被释放。
        ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
        if (prc != null) {
			// 增加引用计数
            incProviderRefLocked(prc, stable);
        }
        return provider;
    }
}

mProviderMap 是一个 ArrayMap 对象,是 ActivityThread 的一个成员变量,表示在该进程记录的 provider 信息。不过,目前它还是一个空的 ArrayMap 对象。

mProviderMap 是一个重要的集合,我们绘制下它的结构图如下:

2.2.6.2 ActivityManagerNative.getDefault() 方法
// ActivityManagerNative 类:
static public IActivityManager getDefault() {
    return gDefault.get();
}

private static final Singleton gDefault = new Singleton() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        IActivityManager am = asInterface(b);
        return am;
    }
};
// 因为这里客户端和服务端不处于同一个进程,所以这个方法返回的是 ActivityManagerProxy 对象。
static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }
    return new ActivityManagerProxy(obj);
}
public abstract class Singleton {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

这里采用的是局部单例技术,保证获取到的 IActivityManager 对象总是一个对象,实际上是 ActivityManagerProxy 对象。

2.2.7 ActivityManagerProxy.getContentProvider() 方法
  • IApplicationThread caller, ActivityThread 的 ApplicationThread 对象 mApplicationThread,是 binder 服务端对象

  • String name, “com.wzc.chapter_9.bookprovider”

  • int userId, 0

  • boolean stable, false

class ActivityManagerProxy implements IActivityManager
{
	public ContentProviderHolder getContentProvider(IApplicationThread caller,
			String name, int userId, boolean stable) throws RemoteException {
		Parcel data = Parcel.obtain();
		Parcel reply = Parcel.obtain();
		data.writeInterfaceToken(IActivityManager.descriptor);
		data.writeStrongBinder(caller != null ? caller.asBinder() : null);
		data.writeString(name);
		data.writeInt(userId);
		data.writeInt(stable ? 1 : 0);
        // 见[【2.2.8】
		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;
	}
}

这个方法仍是在客户端进程调用的。

mRemote.transact() 是客户端进程发起 binder 通信的方法,经过 binder 驱动,最后会到 binder 服务端 ActivityManagerNative的 onTransact() 方法。

这里远程调用返回的 reply 值,最终会转为一个 ContentProviderHolder 对象,返回给客户端调用者。从 ContentProviderHolder 的名字来看,它是 ContentProvider 的持有者或者说 ContentProviderHolder 的容器。

ContentProviderHolder 类是 IActivityManager 接口的嵌套内部类。

public static class ContentProviderHolder implements Parcelable {
    public final ProviderInfo info;
    public IContentProvider provider;
    public IBinder connection;
    public boolean noReleaseNeeded;
    public ContentProviderHolder(ProviderInfo _info) {
        info = _info;
    }
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        info.writeToParcel(dest, 0);
        if (provider != null) {
            dest.writeStrongBinder(provider.asBinder());
        } else {
            dest.writeStrongBinder(null);
        }
        dest.writeStrongBinder(connection);
        dest.writeInt(noReleaseNeeded ? 1:0);
    }
    public static final Parcelable.Creator CREATOR
            = new Parcelable.Creator() {
        @Override
        public ContentProviderHolder createFromParcel(Parcel source) {
            return new ContentProviderHolder(source);
        }
        @Override
        public ContentProviderHolder[] newArray(int size) {
            return new ContentProviderHolder[size];
        }
    };
    private ContentProviderHolder(Parcel source) {
        info = ProviderInfo.CREATOR.createFromParcel(source);
        // 这里拿到把 BinderProxy 对象,转换成了 ContentProviderProxy 对象。
        provider = ContentProviderNative.asInterface(
            source.readStrongBinder());
        connection = source.readStrongBinder();
        noReleaseNeeded = source.readInt() != 0;
    }
}

可以看到,ContentProviderHolder 是一个实现了 Parcelable 接口的类,所以它可以被序列化和反序列化。它封装了 provider 在清单中注册的信息,ContentProviderProxy 对象等。

2.2.8 ActivityManagerNative.onTransact() 方法
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
	@Override
	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();
				// 获取的是 ApplicationThreadProxy 对象
				IApplicationThread app = ApplicationThreadNative.asInterface(b);
				String name = data.readString();
				int userId = data.readInt();
				boolean stable = data.readInt() != 0;
                // 调用到这里,进入 AMS,见【2.2.9】
				ContentProviderHolder cph = getContentProvider(app, name, userId, stable);
				reply.writeNoException();
				if (cph != null) {
					reply.writeInt(1);
					cph.writeToParcel(reply, 0);
				} else {
					reply.writeInt(0);
				}
				return true;
			}
		}
	}
}

这个方法是运行在服务端进程了,在这里是 system_server 进程。

ActivityManagerNative 是抽象类,getContentProvider() 是它的一个抽象方法。

ActivityManagerService 继承了 ActivityManagerNative,实现了 getContentProvider() 这个抽象方法。

2.2.9 ActivityManagerService.getContentProvider() 方法
  • IApplicationThread caller, ApplicationThreadProxy 对象
  • String name, “com.wzc.chapter_9.bookprovider”
  • int userId, 0
  • boolean stable, false
@Override
public final ContentProviderHolder getContentProvider(
        IApplicationThread caller, String name, int userId, boolean stable) {
    enforceNotIsolatedCaller("getContentProvider");
    if (caller == null) {
        throw new SecurityException("");
    }
    // 见【2.2.10】
    return getContentProviderImpl(caller, name, null, stable, userId);
}

该方法的主要作用:检查 IApplicationThread caller 是不是为 null,通过检查后,调用 getContentProviderImpl() 方法。

2.2.10 ActivityManagerService.getContentProviderImpl() 方法
  • IApplicationThread caller, ApplicationThreadProxy 对象
  • String name, “com.wzc.chapter_9.bookprovider”
  • IBinder token, null
  • boolean stable, false
  • int userId, 0
public final class ActivityManagerService extends ActivityManagerNative {
	// ProviderMap 结构,见【2.2.10.1】
	final ProviderMap mProviderMap;
	// mLaunchingProviders 记录客户端正在等待publish的ContentProviderRecord对象
	// 应用当前正在被启动,provider 在被发布后就会从这个列表里面移除掉。
	final ArrayList mLaunchingProviders
			= new ArrayList();
	public ActivityManagerService(Context systemContext) {
		mProviderMap = new ProviderMap(this);
	}
	private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
			String name, IBinder token, boolean stable, int userId) {
		ContentProviderRecord cpr;
		ContentProviderConnection conn = null;
		ProviderInfo cpi = null;
		synchronized(this) {
			long startTime = SystemClock.elapsedRealtime();
			ProcessRecord r = null;
			if (caller != null) { // call 不为 null,进入此分支
				// 获取发起方的进程记录 ProcessRecord 对象
				r = getRecordForAppLocked(caller);
			}
			boolean checkCrossUser = true;
			// 首先,检查这个 provider 是否已经被发布了
			// 本次分析,我们的 provider 还未发布,因此这里会返回 null,cpr 为 null。
			cpr = mProviderMap.getProviderByName(name, userId);
			// userId 是 0,UserHandle.USER_OWNER 也是 0,所以不会进入此分支
			if (cpr == null && userId != UserHandle.USER_OWNER) { 
				...
			}
			boolean providerRunning = cpr != null; // false,表示目标 provider 不存在。
			if (providerRunning) { // providerRunning 为 false,不会进入此分支
				...// 省略掉很多代码,它们与本次分析无关。
			}
			boolean singleton;
			if (!providerRunning) { // 进入此分支
				try {
					// 通过 PKMS 来解析清单文件中的 provider 信息,ProviderInfo 对象
					cpi = AppGlobals.getPackageManager().
						resolveContentProvider(name,
							STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
				} catch (RemoteException ex) {
				}
				if (cpi == null) {
					return null;
				}
				// 本次我们分析的是单实例 provider,因此 singleton 为 true。
				singleton = isSingleton(cpi.processName, cpi.applicationInfo,
						cpi.name, cpi.flags)
						&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
				if (singleton) {
					userId = UserHandle.USER_OWNER;
				}
				// getAppInfoForUser 获取包含用户信息的 ApplicationInfo 对象。 
				cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
				String msg;
				// 检查发起方进程是否有权限获取此 provider
				if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
						!= null) {
					throw new SecurityException(msg);
				}
				...
				ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
				// 根据 class,从 mProviderMap 里面获取 ContentProviderRecord
				// 本次分析,provider 还未发布,所以返回 null,所以 cpr 为 null。
				cpr = mProviderMap.getProviderByClass(comp, userId);
				final boolean firstClass = cpr == null; // firstClass 为 true
				if (firstClass) {
					final long ident = Binder.clearCallingIdentity();
					try {
						ApplicationInfo ai =
							AppGlobals.getPackageManager().
								getApplicationInfo(
										cpi.applicationInfo.packageName,
										STOCK_PM_FLAGS, userId);
						if (ai == null) {
							Slog.w(TAG, "No package info for content provider "
									+ cpi.name);
							return null;
						}
						ai = getAppInfoForUser(ai, userId);
						// 创建 ContentProviderRecord 对象
						cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
					} catch (RemoteException ex) {
					} finally {
						Binder.restoreCallingIdentity(ident);
					}
				}
				// 到这里,ContentProviderRecord cpr 对象一定不会为 null 了。
				// canRunHere 判断 ContentProvider 是否能运行在发起方所在进程
				// 本次分析,canRunHere() 返回 false,见【2.2.10.2】分析
				if (r != null && cpr.canRunHere(r)) { // 不会进入此分支
					return cpr.newHolder(null);
				}
				// 遍历 mLaunchingProviders,如果有元素等于 cpr,就跳出循环。
				final int N = mLaunchingProviders.size();
				int i;
				for (i=0; i= N) { // i >= N,说明上面的循环走完了,没有中途跳出,也就是说,没有发现有元素等于 cpr。
					final long origId = Binder.clearCallingIdentity();
					try {
						try {
							AppGlobals.getPackageManager().setPackageStoppedState(
									cpr.appInfo.packageName, false, userId);
						} catch (RemoteException e) {
						} catch (IllegalArgumentException e) {
						}
						// 获取 provider 所在进程(进程名字:"com.wzc.chapter_9.provider")的进程记录对象
						ProcessRecord proc = getProcessRecordLocked(
								cpi.processName, cpr.appInfo.uid, false);
						// 进程记录存在且其 IApplicationThread 成员存在,则计划安装此provider。	
						// 本次分析,目标进程还没有启动,所以不会进入此分支
						if (proc != null && proc.thread != null) {
							proc.pubProviders.put(cpi.name, cpr);
							try {
								proc.thread.scheduleInstallProvider(cpi);
							} catch (RemoteException e) {
							}
						} else {
							// 否则,开启对应的进程,见【2.2.11】
							proc = startProcessLocked(cpi.processName,
									cpr.appInfo, false, 0, "content provider",
									new ComponentName(cpi.applicationInfo.packageName,
											cpi.name), false, false, false);
							if (proc == null) {
								return null;
							}
						}
                        // 把目标进程对象赋值给 cpr 的 launchingApp 成员变量
						cpr.launchingApp = proc;
						mLaunchingProviders.add(cpr);
					} finally {
						Binder.restoreCallingIdentity(origId);
					}
				}
				if (firstClass) {
					mProviderMap.putProviderByClass(comp, cpr);
				}
				mProviderMap.putProviderByName(name, cpr);
				conn = incProviderCountLocked(r, cpr, token, stable);
				if (conn != null) {
					conn.waiting = true;
				}
			}
		}
        // 循环等待 provider 发布
        // 本次分析,cpr.provider 为 null,因此会进入 while 循环。
		synchronized (cpr) {
			while (cpr.provider == null) {
				if (cpr.launchingApp == null) {
					return null;
				}
				try {
					if (conn != null) {
						conn.waiting = true;
					}
					cpr.wait();
				} catch (InterruptedException ex) {
				} finally {
					if (conn != null) {
						conn.waiting = false;
					}
				}
			}
		}
		return cpr != null ? cpr.newHolder(conn) : null;
	}
}

该方法的主要作用:

  1. 尝试从 AMS 持有的数据结构 mProviderMap 中获取到 ContentProviderRecord 对象;
  2. 如果 1 无法拿到 ContentProviderRecord 对象,说明 provider 还未发布,对发起方进程进行权限检查等 *** 作后,创建一个 ContentProviderRecord 对象;
  3. 检查 provider 是否可以运行在发起方进程里面,本次不可以;
  4. 判断 ContentProviderRecord 是否是客户端在等待发布的,不是,则进入 5,是,则进入 6;
  5. 判断 provider 的目标进程是否存在,不存在,则需要去开启对应的目标进程;
  6. 把 ContentProviderRecord 存到 mProviderMap 数据结构中,增加 provider 引用计数;
  7. 循环等待 provider 发布。
2.2.10.1 ProviderMap 类
public final class ProviderMap {

    private static final String TAG = "ProviderMap";

    private final ActivityManagerService mAm;

	// 全局集合:存放的是单实例的 provider 记录
	// 以 authority 为 key,以 CPR 为 value
    private final HashMap mSingletonByName
            = new HashMap();
	// 以 class 为 key,以 CPR 为 value
    private final HashMap mSingletonByClass
            = new HashMap();

	// 按用户的userId,来管理对应的集合:存放的是多实例的 provider 记录。
    private final SparseArray> mProvidersByNamePerUser
            = new SparseArray>();
    private final SparseArray> mProvidersByClassPerUser
            = new SparseArray>();

    ProviderMap(ActivityManagerService am) {
        mAm = am;
    }

    ContentProviderRecord getProviderByName(String name) {
        return getProviderByName(name, -1);
    }

    ContentProviderRecord getProviderByName(String name, int userId) {
        // 先去全局集合里面查找
        ContentProviderRecord record = mSingletonByName.get(name);
        if (record != null) {
            return record;
        }

        // 再去当前用户的集合里面查找
        return getProvidersByName(userId).get(name);
    }

    ContentProviderRecord getProviderByClass(ComponentName name) {
        return getProviderByClass(name, -1);
    }

    ContentProviderRecord getProviderByClass(ComponentName name, int userId) {
        // 先去全局集合里面查找
        ContentProviderRecord record = mSingletonByClass.get(name);
        if (record != null) {
            return record;
        }

        // 再去当前用户的集合里面查找
        return getProvidersByClass(userId).get(name);
    }

    void putProviderByName(String name, ContentProviderRecord record) {
        if (record.singleton) {
            mSingletonByName.put(name, record);
        } else {
            final int userId = UserHandle.getUserId(record.appInfo.uid);
            getProvidersByName(userId).put(name, record);
        }
    }

    void putProviderByClass(ComponentName name, ContentProviderRecord record) {
        if (record.singleton) {
            mSingletonByClass.put(name, record);
        } else {
            final int userId = UserHandle.getUserId(record.appInfo.uid);
            getProvidersByClass(userId).put(name, record);
        }
    }

    void removeProviderByName(String name, int userId) {
        if (mSingletonByName.containsKey(name)) {
            mSingletonByName.remove(name);
        } else {
            if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
            HashMap map = getProvidersByName(userId);
            map.remove(name);
            if (map.size() == 0) {
                mProvidersByNamePerUser.remove(userId);
            }
        }
    }

    void removeProviderByClass(ComponentName name, int userId) {
        if (mSingletonByClass.containsKey(name)) {
            mSingletonByClass.remove(name);
        } else {
            if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
            HashMap map = getProvidersByClass(userId);
            map.remove(name);
            if (map.size() == 0) {
                mProvidersByClassPerUser.remove(userId);
            }
        }
    }

    private HashMap getProvidersByName(int userId) {
        if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
        final HashMap map = mProvidersByNamePerUser.get(userId);
        if (map == null) {
            HashMap newMap = new HashMap();
            mProvidersByNamePerUser.put(userId, newMap);
            return newMap;
        } else {
            return map;
        }
    }

    HashMap getProvidersByClass(int userId) {
        if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
        final HashMap map
                = mProvidersByClassPerUser.get(userId);
        if (map == null) {
            HashMap newMap
                    = new HashMap();
            mProvidersByClassPerUser.put(userId, newMap);
            return newMap;
        } else {
            return map;
        }
    }
}

虽然这个类的名字叫 ProviderMap,但是它并不是一个 Map 的子类。这个类采用组合的方式,内部管理了 mSingletonByName ,mSingletonByClass,mProvidersByNamePerUser,mProvidersByClassPerUser四个集合对象,并定义了方法来实现元素的添加,获取,删除 *** 作。

思考一下:为什么要使用组合的方式而不是继承的方式来实现 ProviderMap?

因为采用继承的方式,就要受限于父类的接口;而这里要实现对单实例集合和多实例集合的分别管理,采用组合可以达到这种目的。

这个类在后面用的比较多,所以这里重点说明了一下它的结构。

2.2.10.2 ContentProviderRecord.canRunHere() 方法
  • ProcessRecord app, 调用方进程记录对象
final class ContentProviderRecord {
	public final ProviderInfo info;
	final int uid;
	
	public boolean canRunHere(ProcessRecord app) {
		return (info.multiprocess || info.processName.equals(app.processName))
				&& uid == app.info.uid;
	}
}

该方法的主要作用:判断 provider 是否可以运行在调用方进程。需要满足两个条件:

  1. 条件一:provider 在清单文件中设置了 android:multiprocess="true",或者 provider 的进程名字和调用方进程名字一致;
  2. 条件二:provider 的 uid 和调用方进程的 uid 一致。

本次分析,不满足条件一:provider 在清单文件中没有设置 android:multiprocess="true",且provider 的进程名字("com.wzc.chapter_9.provider")和调用方进程名字("com.wzc.chapter_9")不一致,所以这个方法返回 false,即 provider 不可以运行在调用方进程。

2.2.11 ActivityManagerService.startProcessLocked() 方法
  • String processName, “com.wzc.chapter_9.provider”
  • ApplicationInfo info, 清单文件中的 application 节点信息
  • boolean knownToBeDead, false
  • int intentFlags, 为 0,
  • String hostingType, “content provider”
  • ComponentName hostingName, ContentProvider 的组件名对象,即包名 + 类名的组合
  • boolean allowWhileBooting, false
  • boolean isolated, false
  • boolean keepIfLarge false
final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        String hostingType, ComponentName hostingName, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
    return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
            hostingName, allowWhileBooting, isolated, 0 , keepIfLarge,
            null , null , null ,
            null );
}

调用 startProcessLocked 的重载方法:

  • String processName, “com.wzc.chapter_9.provider”
  • ApplicationInfo info, 清单文件中的 application 节点信息
  • boolean knownToBeDead, false
  • int intentFlags, 为 0,
  • String hostingType, “content provider”
  • ComponentName hostingName, ContentProvider 的组件名对象,即包名 + 类名的组合
  • boolean allowWhileBooting, false
  • boolean isolated, false
  • int isolatedUid, 0
  • boolean keepIfLarge false
  • String abiOverride, null
  • String entryPoint, null
  • String[] entryPointArgs, null
  • Runnable crashHandler, null
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
        boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
        boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
        String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
    long startTime = SystemClock.elapsedRealtime();
    ProcessRecord app;
    if (!isolated) { // isolated 为 false,进入此分支
		// 获取进程名为 "com.wzc.chapter_9.provider" 的进程记录对象,这里还没有,所以返回 null。
        app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
    } else {
        ...
    }
	
    if (app != null && app.pid > 0) { // app 为 null,不会进入此分支
        ...
    }
    String hostingNameStr = hostingName != null
            ? hostingName.flattenToShortString() : null;
    if (!isolated) { // 进入此分支
        if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) { // intentFlags 为 0,不会进入此分支
            ...
        } else { // 进入此分支
            mProcessCrashTimes.remove(info.processName, info.uid);
            if (mBadProcesses.get(info.processName, info.uid) != null) {
                mBadProcesses.remove(info.processName, info.uid);
                if (app != null) {
                    app.bad = false;
                }
            }
        }
    }
    if (app == null) { // 进入此分支
		// 创建新的 ProcessRecord 对象,见【2.2.11.1】。
        app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
        app.crashHandler = crashHandler;
        if (app == null) {
            return null;
        }
        mProcessNames.put(processName, app.uid, app);
        ...
    } else {
        ...
    }
	// 如果系统还没有就绪,那么就推迟启动进程直到系统就绪。
    if (!mProcessesReady
            && !isAllowedWhileBooting(info)
            && !allowWhileBooting) {
        if (!mProcessesOnHold.contains(app)) {
            mProcessesOnHold.add(app);
        }
        return app;
    }
	// 启动新进程,见【2.2.12】
    startProcessLocked(
            app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
    return (app.pid != 0) ? app : null;
}

2.2.11.1 ActivityManagerService.newProcessRecordLocked() 方法
  • ApplicationInfo info, 清单文件中的 application 节点信息
  • String customProcess, “com.wzc.chapter_9.provider”
  • boolean isolated, false
  • int isolatedUid, 0
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
        boolean isolated, int isolatedUid) {
    String proc = customProcess != null ? customProcess : info.processName;
    BatteryStatsImpl.Uid.Proc ps = null;
    BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
    int uid = info.uid;
    if (isolated) { // isolated 为 false,所以不会进入此分支
        ...
    }
    return new ProcessRecord(stats, info, proc, uid);
}

该方法的作用:创建了一个 ProcessRecord 对象而已。

2.2.12 ActivityManagerService.startProcessLocked() 方法
  • ProcessRecord app, 新创建的 ProcessRecord 对象
  • String hostingType, “service”
  • String hostingNameStr, Service 的组件名对象转换成的字符串,即"com.wzc.chapter_9/.provider.BookProvider"
  • String abiOverride, null
  • String entryPoint, null
  • String[] entryPointArgs, null
private final void startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
    long startTime = SystemClock.elapsedRealtime();
    if (app.pid > 0 && app.pid != MY_PID) { // app.pid 为 0,不会进入此分支
        ...
    }
    mProcessesOnHold.remove(app);
    updateCpuStats();
    try {
        int uid = app.uid;
        int[] gids = null;
        int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
        if (!app.isolated) { // isolated 为 false,会进入此分支
            ...
        }
        ...
        boolean isActivityProcess = (entryPoint == null); // true
		// entryPoint 是 null,所以 entryPoint 会被赋值为 "android.app.ActivityThread"
        if (entryPoint == null) entryPoint = "android.app.ActivityThread";
		// 开启进程:请求 zygote 去开启进程,见[2.2.13]
        Process.ProcessStartResult startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
                app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                app.info.dataDir, entryPointArgs);
        ...
		// 设置 ProcessRecord app 的成员变量
        app.setPid(startResult.pid);
        app.usingWrapper = startResult.usingWrapper;
        app.removed = false;
        app.killed = false;
        app.killedByAm = false;
        synchronized (mPidsSelfLocked) {
            // 存储新进程的 pid 和 ProcessRecord 对象键值对到 mPidsSelfLocked。
            this.mPidsSelfLocked.put(startResult.pid, app);
            if (isActivityProcess) {
                Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                msg.obj = app;
                mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                        ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
            }
        }
    } catch (RuntimeException e) {
		...
    }
}
2.2.13 Process.start() 方法
  • final String processClass, “android.app.ActivityThread”
  • final String niceName, “com.wzc.chapter_9.provider”
  • int uid,
  • int gid,
  • int[] gids,
  • int debugFlags,
  • int mountExternal,
  • int targetSdkVersion, 目标 sdk 版本
  • String seInfo,
  • String abi, 架构
  • String instructionSet, 指令集
  • String appDataDir,
  • String[] zygoteArgs, null
public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] zygoteArgs) {
    try {
		// 通过 zygote 开启进程
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
        throw new RuntimeException(
                "Starting VM process through Zygote failed", ex);
    }
}

system_server 进程里,调用 Process.start() 方法,通过 socket 向 zygote 进程发送创建新进程的请求;

在 zygote 进程里面,在执行ZygoteInit.main()后便进入runSelectLoop()循环体内,当有客户端连接时便会执行ZygoteConnection.runonce()方法,再经过层层调用后 fork 出新的应用进程;

新的进程创建后,执行handleChildProc方法,最后调用ActivityThread.main()方法。

这部分详细请参考理解Android进程创建流程-袁辉辉。

本文会直接跳到 ActivityThread.main() 方法继续分析。

2.2.14 ActivityThread.main() 方法
public static void main(String[] args) {
    ...
    // 准备主线程的 Looper 对象
    Looper.prepareMainLooper();
	// 创建 ActivityThread 对象
    ActivityThread thread = new ActivityThread();
	// 调用 ActivityThread 对象的 attach 方法
    thread.attach(false);
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    AsyncTask.init();
    // 运行消息队列
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}
2.2.15 ActivityThread.attach() 方法
  • boolean system, false,表示不是系统进程,而是普通应用进程
private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) { // system 为 false,进入此分支
        ...
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        // mgr 实际上是 ActivityManagerProxy 对象
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            // Ignore
        }
        ...
    } else {
        ...
    }
    ...
}
2.2.16 ActivityManagerService.attachApplication() 方法
  • IApplicationThread thread, ApplicationThreadProxy 对象
@Override
public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}
2.2.17 ActivityManagerService.attachApplicationLocked() 方法
  • IApplicationThread thread, ApplicationThreadProxy 对象
  • int pid, provider 进程的 pid
// 存储了所有运行的进程,以pid为键,以ProcessRecord为值
final SparseArray mPidsSelfLocked = new SparseArray();
private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {
    ProcessRecord app;
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
			// 根据 pid,获取到之前存储的 ProcessRecord 对象,不为 null。
            app = mPidsSelfLocked.get(pid);
        }
    } else {
        app = null;
    }
    if (app == null) { // 不会进入此分支
       ...
    }
    if (app.thread != null) { // app.thread 目前为 null,不会进入此分支
        handleAppDiedLocked(app, true, true);
    }
    ...
	// mProcessesReady 为 true,所以这里 normalMode 为 true
    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); 
	// 获取清单文件中注册的 provider 信息
    List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
    try {
        ...
        ApplicationInfo appInfo = app.instrumentationInfo != null
                ? app.instrumentationInfo : app.info;
        app.compat = compatibilityInfoForPackageLocked(appInfo);
        if (profileFd != null) {
            profileFd = profileFd.dup();
        }
        ProfilerInfo profilerInfo = profileFile == null ? null
                : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
		// 调用到这里,thread 是 ApplicationThreadProxy 对象,见【2.2.18】
        thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
                mCoreSettingsObserver.getCoreSettingsLocked());
        updateLruProcessLocked(app, false, null);
        app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
    } catch (Exception e) {
        ...
    }
    ...// 省略与本次分析无关的代码
    return true;
}
2.2.17.1 ActivityManagerService.generateApplicationProvidersLocked() 方法
private final List generateApplicationProvidersLocked(ProcessRecord app) {
    List providers = null;
    try {
		// 获取清单文件中注册的 provider 信息列表
        providers = AppGlobals.getPackageManager().
            queryContentProviders(app.processName, app.uid,
                    STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
    } catch (RemoteException ex) {
    }
    int userId = app.userId;
    if (providers != null) {
        int N = providers.size();
        app.pubProviders.ensureCapacity(N + app.pubProviders.size());
        for (int i=0; i 
2.2.18 ApplicationThreadProxy.bindApplication() 方法 
public final void bindApplication(...) throws RemoteException {
    ...
    mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
            IBinder.FLAG_ONEWAY);
    data.recycle();
}

这个方法仍是在 system_server 进程(是 binder 客户端进程)调用的。

mRemote.transact() 是 system_server 进程发起 binder 通信的方法,经过 binder 驱动,最后会到 provider 的目标进程(是 binder 服务端)ApplicationThreadNative的 onTransact() 方法。

2.2.19 ApplicationThreadNative.onTransact() 方法
public abstract class ApplicationThreadNative extends Binder
        implements IApplicationThread {
	@Override
	public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
			throws RemoteException {
		case BIND_APPLICATION_TRANSACTION:
		{
			...
            // 调用到这里,见【2.2.20】
			bindApplication(packageName, info, providers, testName, profilerInfo, testArgs,
					testWatcher, uiAutomationConnection, testMode, openGlTrace,
					restrictedBackupMode, persistent, config, compatInfo, services, coreSettings);
			return true;
		}				
	}			
}

这个方法是运行在 provider 的目标进程里的。

ApplicationThreadNative 是一个抽象类,而 bindApplication()是它的一个抽象方法。

ApplicationThread 是继承于 ApplicationThreadNative 的具体类,它实现了 bindApplication() 方法。

ApplicationThread 类是 ActivityThread 的私有内部类。

2.2.20 ApplicationThread.bindApplication() 方法
public final void bindApplication(...) {
    ...
    // 把信息封装在 AppBindData 里,通过 handler 发送到主线程。
    AppBindData data = new AppBindData();
    data.processName = processName;
    data.appInfo = appInfo;
    data.providers = providers;
	...
    sendMessage(H.BIND_APPLICATION, data);
}

这个方法目前是运行在 provider 的目标进程的 binder 线程池里面的。

2.2.21 H.handleMessage() 方法
public final class ActivityThread {
	final H mH = new H();
	private class H extends Handler {
		public void handleMessage(Message msg) {
			case BIND_APPLICATION:
				AppBindData data = (AppBindData)msg.obj;
				handleBindApplication(data);
				break;
		}
	}
}

这个方法目前是运行在 provider 的目标进程的主线程里面的。

2.2.22 ActivityThread.handleBindApplication() 方法
private void handleBindApplication(AppBindData data) {
	...
    // 获取 LoadedApk 对象,赋值给 data.info
    data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
	// 来自 ProcessRecord 的 instrumentationClass,这个值只有在 AMS 的 startInstrumentation() 方法里赋值了
	// 所以,本次分析 data.instrumentationName 为 null,不会进入 if 分支
    if (data.instrumentationName != null) { 
		...
    } else {
		// 创建 Instrumentation 对象
        mInstrumentation = new Instrumentation();
    }
    try {
		// 创建 Application 对象
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;
        // don't bring up providers in restricted mode; they may depend on the
        // app's custom Application class
        if (!data.restrictedBackupMode) { // 非限制模式,进入 if 分支
			// 获取清单中注册的 provider 信息列表
            List providers = data.providers;
            if (providers != null) {
				// 安装 content providers,见【2.2.23】
                installContentProviders(app, providers);
            }
        }
        try {
			// 内部会调用 app.onCreate() 方法
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {}
    } finally {}
}

该方法的主要作用:

  1. 创建 Instrumentation 对象;
  2. 创建 Application 对象;
  3. 安装 content providers:创建 provider 对象,回调了 provider 的 onCreate() 方法,并存储了 provider 信息到对应的数据结构中;
  4. 回调 Application 对象的 onCreate() 方法。

从这里可以知道,ContentProvider 的 onCreate() 方法在 Application 的 onCreate() 方法之前回调。

而ContentProvider 的 onCreate() 方法是在主线程调用的,那么如果在 ContentProvider 的 onCreate() 方法里执行了耗时 *** 作,势必会推迟Application 的 onCreate() 方法的回调,也就是说,推迟了应用的初始化 *** 作了,对于用户来说,就是应用启动缓慢了,这多么不好啊。

所以,一定不要在 ContentProvider 的 onCreate() 方法里面执行耗时 *** 作。

2.2.23 ActivityThread.installContentProviders() 方法
  • Context context, provider 进程的 Application 对象
  • List providers, 清单文件中的 provider 信息列表
private void installContentProviders(
        Context context, List providers) {
    final ArrayList results =
        new ArrayList();
	// 遍历清单文件中的 provider 信息列表
    for (ProviderInfo cpi : providers) {
		// 安装每一个 provider,本次分析我们只有一个 provider 待安装,见【2.2.24】
        IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                false , true , true );
        if (cph != null) {
            cph.noReleaseNeeded = true;
            results.add(cph);
        }
    }
    try {
        // 见【2.2.25】
        // ActivityManagerNative.getDefault() 是一个 ActivityManagerProxy 对象,通过它,经过 binder 驱动,向 binder 服务端的 AMS 发起远程调用。
        ActivityManagerNative.getDefault().publishContentProviders(
            getApplicationThread(), results);
    } catch (RemoteException ex) {
    }
}

该方法的主要作用:

  1. 安装 provider;
  2. 发布安装结果:由 provider 目标进程向 system_server 进程的 AMS 发起远程请求。
2.2.24 ActivityThread.installProvider() 方法
  • Context context, provider 进程的 Application 对象
  • IActivityManager.ContentProviderHolder holder, null
  • ProviderInfo info, 清单文件中的 provider 信息
  • boolean noisy, false
  • boolean noReleaseNeeded, true
  • boolean stable, true
// 在 2.2.6.2 中,我们绘制了这个集合的结构图
final ArrayMap mProviderMap
    = new ArrayMap();
final ArrayMap mLocalProvidersByName
        = new ArrayMap();	
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 分支
		...
        try {
            final java.lang.ClassLoader cl = c.getClassLoader();
			// 反射创建 ContentProvider 对象,本次分析创建的是 BookProvider 对象。
            localProvider = (ContentProvider)cl.
                loadClass(info.name).newInstance();
			// 这里获取的是 Transport 对象,是 IContentProvider 接口的 binder 服务端对象。
            provider = localProvider.getIContentProvider();
			// 把 Context 对象和 ContentProvider 相关联,并回调 BookProvider 对象的 onCreate() 方法,见【2.2.24.1】
            localProvider.attachInfo(c, info);
        } catch (java.lang.Exception e) {}
    } else {
        ...
    }
    IActivityManager.ContentProviderHolder retHolder;
    synchronized (mProviderMap) {
        IBinder jBinder = provider.asBinder();
        if (localProvider != null) { // 进入此 if 分支
            ComponentName cname = new ComponentName(info.packageName, info.name);
            ProviderClientRecord pr = mLocalProvidersByName.get(cname);
            if (pr != null) {
                provider = pr.mProvider;
            } else { // 进入 else 分支
                holder = new IActivityManager.ContentProviderHolder(info);
                holder.provider = provider;
                holder.noReleaseNeeded = true;
				// 把 provider 存储在 mProviderMap 里面,见【2.2.24.2】
                pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                mLocalProviders.put(jBinder, pr);
                mLocalProvidersByName.put(cname, pr);
            }
            retHolder = pr.mHolder;
        } else {
            ...
        }
    }
    return retHolder;
}

该方法的主要作用:

  1. 通过反射创建 ContentProvider 对象;
  2. 通过 ContentProvider.attachInfo() 方法把 Context 对象和 ContentProvider 相关联,并回调 BookProvider 对象的 onCreate() 方法;
  3. 存储 provider 信息到相关的数据结构中。
2.2.24.1 ContentProvider.attachInfo() 方法
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
    // 保证 mContext 对象只被设置一次,这样 onCreate() 方法也是只会调用一次了。
    if (mContext == null) {
        mContext = context;
        ...
        // 回调 BookProvider 的 onCreate() 方法
        ContentProvider.this.onCreate();
    }
}

该方法的主要作用:把 Context 对象和 ContentProvider 相关联,并回调 BookProvider 对象的 onCreate() 方法。

2.2.24.2 ActivityThread.installProviderAuthoritiesLocked() 方法
  • IContentProvider provider, ContentProvider 的 Transport 对象
  • ContentProvider localProvider, BookProvider 对象
  • IActivityManager.ContentProviderHolder holder,
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
        ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
    final String auths[] = PATTERN_SEMIcolon.split(holder.info.authority);
    final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
    // 把 holder 封装在 ProviderClientRecord 对象里面。
    final ProviderClientRecord pcr = new ProviderClientRecord(
            auths, provider, localProvider, holder);
    for (String auth : auths) {
        final ProviderKey key = new ProviderKey(auth, userId);
        final ProviderClientRecord existing = mProviderMap.get(key);
        if (existing != null) {
            Slog.w(TAG, "Content provider " + pcr.mHolder.info.name
                    + " already published as " + auth);
        } else {
			// 把对应的 ProviderKey 和 ProviderClientRecord 存储在 mProviderMap 集合里面。
            mProviderMap.put(key, pcr);
        }
    }
    return pcr;
}
2.2.25 ActivityManagerService.publishContentProviders() 方法
  • IApplicationThread caller, provider 目标进程的 ApplicationThread 对象
  • List providers, ContentProviderHolder 列表
public final void publishContentProviders(IApplicationThread caller,
        List providers) {
    if (providers == null) {
        return;
    }
    synchronized (this) {
		// 获取 provider 目标进程的进程记录对象,已存在,所以 r 不为 null。
        final ProcessRecord r = getRecordForAppLocked(caller);
        final int N = providers.size();
        for (int i=0; i pubProviders
			// 			= new ArrayMap();
			// src.info.name 是 provider 的类名称
			// 此处 dst 不为 null,因为在 2.2.17.1 中已经添加了 provider 信息到这个集合里面了。
            ContentProviderRecord dst = r.pubProviders.get(src.info.name);
            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);
                }
                ...
                synchronized (dst) {
					// 这行代码非常关键,把 ContentProviderHolder src 的 provider 对象赋值给
					// ContentProviderRecord dst 的 provider 变量。
                    dst.provider = src.provider;
					// 把 provider 的目标进程记录对象赋值给 ContentProviderRecord dst 的 proc 变量。
                    dst.proc = r;
                    dst.notifyAll();
                }
            }
        }
    }
}
2.2.26 ActivityManagerService.getContentProviderImpl() 方法跳出循环等待 provider 发布

回到 2.2.10 的分析部分:

public final class ActivityManagerService extends ActivityManagerNative {
	final ProviderMap mProviderMap;
	final ArrayList mLaunchingProviders
			= new ArrayList();
	public ActivityManagerService(Context systemContext) {
		mProviderMap = new ProviderMap(this);
	}
	private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
			String name, IBinder token, boolean stable, int userId) {
		ContentProviderRecord cpr;
		ContentProviderConnection conn = null;
		ProviderInfo cpi = null;
		...
        // 循环等待 provider 发布
        // 到这里,cpr.provider 不为 null,因此会结束 while 循环。
		synchronized (cpr) {
			while (cpr.provider == null) {
				if (cpr.launchingApp == null) {
					return null;
				}
				try {
					if (conn != null) {
						conn.waiting = true;
					}
					cpr.wait();
				} catch (InterruptedException ex) {
				} finally {
					if (conn != null) {
						conn.waiting = false;
					}
				}
			}
		}
        // 把 cpr 封装成 ContentProviderHolder 对象返回
		return cpr != null ? cpr.newHolder(conn) : null;
	}
}
2.2.27 ActivityThread.acquireProvider() 方法

回到 2.2.6 的部分分析:

public final IContentProvider acquireProvider(
        Context c, String auth, int userId, boolean stable) {
	...
    IActivityManager.ContentProviderHolder holder = null;
    try {
		// 这个方法会获取到结果 ContentProviderHolder 对象
        holder = ActivityManagerNative.getDefault().getContenProvider(
                getApplicationThread(), auth, userId, stable)
    } catch (RemoteException ex) {
    }
    if (holder == null) { // 不会进入此分支
        // 如果 AMS 返回的 ContentProviderHolder 对象为 null,则直接返回 null。
        return null;
    }
	// 安装 provider 将会增加引用计数,并且打破竞争中的任何联系。见【2.2.27.1】
    holder = installProvider(c, holder, holder.info,
            true , holder.noReleaseNeeded, stable);
    return holder.provider;
}

这个方法执行完毕,就获得了 ContentProviderProxy 对象了。

2.2.27.1 ActivityThread.installProvider() 方法

虽然我们在 2.2.24 中也分析了这个方法,但是和这里是有区别的:

2.2.24 中的 installProvider方法是发生在 provider 目标进程的主线程;

这里的 installProvider 方法是发生在客户端进程的主线程。

  • Context context, ContextImpl 对象
  • IActivityManager.ContentProviderHolder holder, 不为 null
  • ProviderInfo info, 清单文件中的 provider 信息
  • boolean noisy, true
  • boolean noReleaseNeeded, true
  • boolean stable, false
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 分支
        ...
    } else { // 命中 else 分支
        provider = holder.provider;
    }
    IActivityManager.ContentProviderHolder retHolder;
    synchronized (mProviderMap) {
        IBinder jBinder = provider.asBinder();
        if (localProvider != null) { // localProvider 为 null,不会进入 if 分支
            ...
        } else { // 进入 else 分支
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
            if (prc != null) { // prc 为 null,不会进入 if 分支
                ...
            } else { // 进入 else 分支
                ProviderClientRecord client = installProviderAuthoritiesLocked(
                        provider, localProvider, holder);
                if (noReleaseNeeded) { // 进入 if 分支
                    prc = new ProviderRefCount(holder, client, 1000, 1000);
                } else {
                    ...
                }
                mProviderRefCountMap.put(jBinder, prc);
            }
            retHolder = prc.holder;
        }
    }
    return retHolder;
}

该方法的作用:把 provider 信息存入 mProviderMap 集合和 mProviderRefCountMap 集合中。

2.2.27.2 ActivityThread.installProviderAuthoritiesLocked() 方法
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
        ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
    final String auths[] = PATTERN_SEMIcolon.split(holder.info.authority);
    final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
    final ProviderClientRecord pcr = new ProviderClientRecord(
            auths, provider, localProvider, holder);
    for (String auth : auths) {
        final ProviderKey key = new ProviderKey(auth, userId);
        final ProviderClientRecord existing = mProviderMap.get(key);
        if (existing != null) {
            Slog.w(TAG, "Content provider " + pcr.mHolder.info.name
                    + " already published as " + auth);
        } else {
            mProviderMap.put(key, pcr);
        }
    }
    return pcr;
}

该方法的作用:把 provider 信息存入 mProviderMap 集合中。

2.2.28 ContentProviderProxy.query() 方法
final class ContentProviderProxy implements IContentProvider
{
	public Cursor query(String callingPkg, Uri url, String[] projection, String selection,
			String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
					throws RemoteException {
		// 实例化 BulkCursorToCursorAdaptor 对象
		BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
		Parcel data = Parcel.obtain();
		Parcel reply = Parcel.obtain();
		try {
			...
			data.writeStrongBinder(adaptor.getObserver().asBinder());
			data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
			mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
			DatabaseUtils.readExceptionFromParcel(reply);
			if (reply.readInt() != 0) {
				BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
				adaptor.initialize(d);
			} else {
				adaptor.close();
				adaptor = null;
			}
			return adaptor;
		} 
	}	
}

这个方法是运行在客户端进程的。

mRemote.transact() 是 客户端进程发起 binder 通信的方法,经过 binder 驱动,最后会到 provider 的目标进程(是 binder 服务端)ContentProviderNative的 onTransact() 方法。

2.2.29 ContentProviderNative.onTransact() 方法
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
	case QUERY_TRANSACTION:
	{
		...
		Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
				sortOrder, cancellationSignal);
		if (cursor != null) {
			CursorToBulkCursorAdaptor adaptor = null;
			try {
				adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
						getProviderName());
				cursor = null;
				BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
				adaptor = null;
				reply.writeNoException();
				reply.writeInt(1);
				d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
			} finally {}
		} else {
			reply.writeNoException();
			reply.writeInt(0);
		}
		return true;
	}
}

ContentProviderNative 是一个抽象类,query方法是它的一个抽象方法。

ContentProvider.Transport 是 ContentProviderNative 的具体实现类。

2.2.30 Transport.query() 方法
@Override
public Cursor query(String callingPkg, Uri uri, String[] projection,
        String selection, String[] selectionArgs, String sortOrder,
        ICancellationSignal cancellationSignal) {
    validateIncomingUri(uri);
    uri = getUriWithoutUserId(uri);
    if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
        return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
                CancellationSignal.fromTransport(cancellationSignal));
    }
    final String original = setCallingPackage(callingPkg);
    try {
        // 这里调用的就是 BookProvider 的 query 方法了。
        return ContentProvider.this.query(
                uri, projection, selection, selectionArgs, sortOrder,
                CancellationSignal.fromTransport(cancellationSignal));
    } finally {
        setCallingPackage(original);
    }
}
2.2.31 BookProvider.query() 方法
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
    final int code = MATCHER.match(uri);
    if (code == CODE_BOOK_DIR || code == CODE_BOOK_ITEM) {
        Context context = getContext();
        if (context == null) {
            return null;
        }
        BookDao bookDao = AppDatabase.getInstance(context).bookDao();
        final Cursor cursor;
        if (code == CODE_BOOK_DIR) {
            cursor = bookDao.queryAll();
        } else {
            cursor = bookDao.queryById(ContentUris.parseId(uri));
        }
        cursor.setNotificationUri(context.getContentResolver(), uri);
        return cursor;
    } else {
        throw new IllegalArgumentException("Unknown URI: " + uri);
    }
}
3.最后

本文到这里就结束了,希望能够帮助到大家。

关于本文需要讨论的地方,可以在评论区留言讨论。

4.参考
  1. 理解ContentProvider原理-袁辉辉
  2. ContentProvider引用计数-袁辉辉
  3. Android Cursor浅析

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5695655.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存