ContentProvider-概述

Post on Oct 01, 2022 by Wei Lin

概述

ContentProvider作用

ContentProvider的作用是为不同的应用之间数据共享,提供统一的接口。安卓系统中应用内部的数据是对外隔离的,要想让其它应用能使用自己的数据(例如通讯录),就需要用到ContentProvider。

ContentProvider通过uri来标识其它应用要访问的数据,通过ContentResolver的增、删、改、查方法实现对共享数据的操作。还可以通过注册ContentObserver来监听数据是否发生了变化来对应的刷新页面。

ContentProvider的优点:

  • 为数据访问提供统一接口
  • 跨进程数据的访问

ContentProvider的缺点:

  • 不能单独使用,必须与其他存储方式结合使用

ContentResolver作用

如果想要访问内容提供器中共享的数据,就一定要借助ContentResolver 类,可以通过Context中的getContentResolver()方法获取到该类的实例。 ContentResolver 中提供了一系列的方法用于对数据进行CRUD操作。

ContentObserver作用

内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它,并执行相应的操作(如刷新页面)。

Provider的Binder架构

如:应用进程A访问进程B提供的Provider

  • 访问端:进程A
  • AMS端:是上图中的Binder客户端,访问进程B提供的Provider;
  • 服务端B:ContentProvider是个抽象类,通过内部类Transport继承了ContentProviderNative,用户端进程B发布Provider时需要继承ContentProvider,这样Provider架构的服务端就实现了。

AMS在获取Provider的引用(在ContentProviderHolder对象中)后,传递给进程A。

常用类和成员

一图解惑之Android管理ContentProvider结构

简介

对象 说明
ActivityThread.ProviderKey 标识一个Provider资源,用作mProviderMap的Key
ActivityThread.ProviderRefCount 保存一个Provider的引用数
   
ContentProviderConnection 表示一个客户端和Provider之间的连接
ContentProviderHolder 保存ContentProvider的信息和ContentProvider的调用接口,并在SystemServer和App进程间传递
ContentProviderRecord 对应一个ContentProvider,表示一个Provider及其相关属性
   
IContentProvider 表示一个ContentProvider的远程调用接口
ProviderInfo 一个Provider的相关信息,由PackageManager.resolveContentProvider()返回

ActivityThread

ActivityThread中与Provider相关的对象如下。

(1) mProviderMap

final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
    = new ArrayMap<ProviderKey, ProviderClientRecord>();

保存当前进程已经访问过的ContentProvider或是当前进程内自己定义的ContentProvider。

(2) mLocalProviders

final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
    = new ArrayMap<IBinder, ProviderClientRecord>();

保存当前进程内自己定义的ContentProvider

(3) mLocalProvidersByName

final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
        = new ArrayMap<ComponentName, ProviderClientRecord>();

与mLocalProviders中保存的ProviderClientRecord对象相同,只不过用ComponentName作为键值。

(4) mGetProviderKeys

final ArrayMap<ProviderKey, ProviderKey> mGetProviderKeys = new ArrayMap<>();

只在以下代码中用到了

private ProviderKey getGetProviderKey(String auth, int userId) {
    final ProviderKey key = new ProviderKey(auth, userId);
    synchronized (mGetProviderKeys) {
        ProviderKey lock = mGetProviderKeys.get(key);
        if (lock == null) {
            lock = key;
            mGetProviderKeys.put(key, lock);
        }
        return lock;
    }
}

只是保存ProviderKey,暂不知道其作用。

ContentProviderConnection

该对象表示一个客户端和Provider之间的连接。

public final ContentProviderRecord provider;
public final ProcessRecord client;
public final String clientPackage;
public AssociationState.SourceState association;
public final long createTime;
private Object mProcStatsLock;  // Internal lock for accessing AssociationState

/**
 * Internal lock that guards access to the two counters.
 */
private final Object mLock = new Object();
@GuardedBy("mLock")
private int mStableCount;
@GuardedBy("mLock")
private int mUnstableCount;
// The client of this connection is currently waiting for the provider to appear.
// Protected by the provider lock.
public boolean waiting;
// The provider of this connection is now dead.
public boolean dead;

// The original user id when this connection was requested, it could be different from
// the client's user id because the client could request to access a content provider
// living in a different user if it has the permission.
@UserIdInt final int mExpectedUserId;

// For debugging.
private int mNumStableIncs;
private int mNumUnstableIncs;

ContentProviderHelper

在此类中实质上查询Provider,对已发布的Provider返回对象,未发布的作拉起进程等处理。

成员 说明
ArrayList mLaunchingProviders 保存正在启动中的Provider(有客户端正在等待),一旦发布成功就会从这里移除
ProviderMap mProviderMap 保存已发布的Provider对象ContentProviderRecord
boolean mSystemProvidersInstalled 表示system_server进程的相关Provider是否安装,在系统启动时执行并赋值true
/**
 * Activity manager code dealing with content providers.
 */
public class ContentProviderHelper {
    private static final String TAG = "ContentProviderHelper";

    private final ActivityManagerService mService;

    /**
     * List of content providers who have clients waiting for them.  The
     * application is currently being launched and the provider will be
     * removed from this list once it is published.
     */
    private final ArrayList<ContentProviderRecord> mLaunchingProviders = new ArrayList<>();
    private final ProviderMap mProviderMap;
    private boolean mSystemProvidersInstalled;

    ContentProviderHelper(ActivityManagerService service, boolean createProviderMap) {
        mService = service;
        mProviderMap = createProviderMap ? new ProviderMap(mService) : null;
    }
    //......
}

ContentProviderHolder

作用:主要是保存ContentProvider的信息和ContentProvider的调用接口,并在SystemServer和App进程间传递。

对象 说明
ProviderInfo info 描述该ContentProvider的信息
IContentProvider provider 该ContentProvider的调用接口,是一个Binder对象
IBinder connection 实际是一个ContentProviderConnection对象
boolean noReleaseNeeded 应该是表示该Provider使用之后,是否需要移除的意思
boolean mLocal Whether the provider here is a local provider or not.
public final ProviderInfo info;

public IContentProvider provider;
public IBinder connection;

public boolean noReleaseNeeded;

/**
 * Whether the provider here is a local provider or not.
 */
public boolean mLocal;

ContentProviderRecord

作用:对应一个ContentProvider,表示一个Provider及其相关属性。

// Maximum attempts to bring up the content provider before giving up.
static final int MAX_RETRY_COUNT = 3;

final ActivityManagerService service;
public final ProviderInfo info;
final int uid;
final ApplicationInfo appInfo;
final ComponentName name;
final boolean singleton;
public IContentProvider provider;
public boolean noReleaseNeeded;
// All attached clients
final ArrayList<ContentProviderConnection> connections
        = new ArrayList<ContentProviderConnection>();
//final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
// Handles for non-framework processes supported by this provider
ArrayMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
// Count for external process for which we have no handles.
int externalProcessNoHandleCount;
int mRestartCount; // number of times we tried before bringing up it successfully.
ProcessRecord proc; // if non-null, hosting process.
ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
String stringName;
String shortStringName;

IContentProvider

表示一个远程的(非本进程)的Provider对象,是一个Binder引用。

ProviderKey

作用:在客户端的ActivityThread对象中标识一个Provider资源,通过这个Key记录一个Provider的信息(即ProviderKey的属性)。

ProviderKey是ActivityThread.java中的静态内部类。

private static final class ProviderKey {
    final String authority;
    final int userId;

    @GuardedBy("mLock")
    ContentProviderHolder mHolder; // Temp holder to be used between notifier and waiter
    final Object mLock; // The lock to be used to get notified when the provider is ready

    public ProviderKey(String authority, int userId) {
        this.authority = authority;
        this.userId = userId;
        this.mLock = new Object();
    }

    @Override
    public boolean equals(@Nullable Object o) {
        if (o instanceof ProviderKey) {
            final ProviderKey other = (ProviderKey) o;
            return Objects.equals(authority, other.authority) && userId == other.userId;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return ((authority != null) ? authority.hashCode() : 0) ^ userId;
    }
}

getGetProviderKey()方法是根据Provider的auth和userId创建一个ProviderKey,然后再到mGetProviderKeys中查询该mGetProviderKeys是否存在,不存在则将新建的ProviderKey加入。

private ProviderKey getGetProviderKey(String auth, int userId) {
    final ProviderKey key = new ProviderKey(auth, userId);
    synchronized (mGetProviderKeys) {
        ProviderKey lock = mGetProviderKeys.get(key);
        if (lock == null) {
            lock = key;
            mGetProviderKeys.put(key, lock);
        }
        return lock;
    }
}