IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android筑基——ContentProvider 的跨进程启动过程和数据操作方法调用过程(基于api21) -> 正文阅读

[移动开发]Android筑基——ContentProvider 的跨进程启动过程和数据操作方法调用过程(基于api21)

目录

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 的跨进程启动过程,这样我们就可以知道为什么 ContentProvideronCreate() 方法要先于 ApplicationonCreate() 方法执行;
  • ContentProvider 的数据操作方法调用过程,这里以 query(查询)方法为例来说明,这样可以知道由 ContentResolverquery 方法发起的查询操作如何最终交由 ContentProviderquery 方法来执行。

2.正文

2.1 小例子

例子部分请查看BookProvider

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

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

2.2 代码分析

2.2.1 ContextWrapper.getContentResolver() 方法

@Override
public ContentResolver getContentResolver() {
    return mBase.getContentResolver();
}

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

调用装饰类 ContextWrappergetContentResolver()方法,内部真正调用的是核心实现类 ContextImplgetContentResolver()方法。所以 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 /*noisy*/, 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<ProviderKey, ProviderClientRecord> mProviderMap
    = new ArrayMap<ProviderKey, ProviderClientRecord>();
	
final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
    = new ArrayMap<IBinder, ProviderRefCount>();
	
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<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    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<T> {
    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 服务端 ActivityManagerNativeonTransact() 方法。

这里远程调用返回的 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<ContentProviderHolder> CREATOR
            = new Parcelable.Creator<ContentProviderHolder>() {
        @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<ContentProviderRecord> mLaunchingProviders
			= new ArrayList<ContentProviderRecord>();
	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++) {
					if (mLaunchingProviders.get(i) == cpr) {
						break;
					}
				}
				if (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<String, ContentProviderRecord> mSingletonByName
            = new HashMap<String, ContentProviderRecord>();
	// 以 class 为 key,以 CPR 为 value
    private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass
            = new HashMap<ComponentName, ContentProviderRecord>();

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

    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<String, ContentProviderRecord> 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<ComponentName, ContentProviderRecord> map = getProvidersByClass(userId);
            map.remove(name);
            if (map.size() == 0) {
                mProvidersByClassPerUser.remove(userId);
            }
        }
    }

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

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

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

思考一下:为什么要使用组合的方式而不是继承的方式来实现 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 /* isolatedUid */, keepIfLarge,
            null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
            null /* crashHandler */);
}

调用 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<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
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<ProviderInfo> 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<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
    List<ProviderInfo> 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<N; i++) {
            ProviderInfo cpi =
                (ProviderInfo)providers.get(i);            
            ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
            ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
            if (cpr == null) {
                cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
                mProviderMap.putProviderByClass(comp, cpr);
            }
			// 把 provider 信息添加到 ProcessRecord 的 pubProviders ArrayMap 里面。
            app.pubProviders.put(cpi.name, cpr);
            if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
                app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
                        mProcessStats);
            }
        }
    }
    return providers;
}

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 服务端)ApplicationThreadNativeonTransact() 方法。

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<ProviderInfo> 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() 方法。

从这里可以知道,ContentProvideronCreate() 方法在 ApplicationonCreate() 方法之前回调。

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

所以,一定不要在 ContentProvideronCreate() 方法里面执行耗时操作。

2.2.23 ActivityThread.installContentProviders() 方法

  • Context context, provider 进程的 Application 对象
  • List providers, 清单文件中的 provider 信息列表
private void installContentProviders(
        Context context, List<ProviderInfo> providers) {
    final ArrayList<IActivityManager.ContentProviderHolder> results =
        new ArrayList<IActivityManager.ContentProviderHolder>();
	// 遍历清单文件中的 provider 信息列表
    for (ProviderInfo cpi : providers) {
		// 安装每一个 provider,本次分析我们只有一个 provider 待安装,见【2.2.24】
        IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
        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<ProviderKey, ProviderClientRecord> mProviderMap
    = new ArrayMap<ProviderKey, ProviderClientRecord>();
final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
        = new ArrayMap<ComponentName, ProviderClientRecord>();	
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<ContentProviderHolder> 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<N; i++) {
            ContentProviderHolder src = providers.get(i);
            if (src == null || src.info == null || src.provider == null) {
                continue;
            }
			// r.pubProviders 是 
			// final ArrayMap<String, ContentProviderRecord> pubProviders
			// 			= new ArrayMap<String, ContentProviderRecord>();
			// 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<ContentProviderRecord> mLaunchingProviders
			= new ArrayList<ContentProviderRecord>();
	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 /*noisy*/, 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 服务端)ContentProviderNativeonTransact() 方法。

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.TransportContentProviderNative 的具体实现类。

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浅析

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-03 16:13:34  更:2022-01-03 16:16:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:17:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码