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原理 -> 正文阅读

[移动开发]Android ContentProvider原理

简介

基于Android 9.0的源码剖析, 分析Android ContentProvider原理。

一、概述

ContentProvider作为四大组件之一,在开发过程中经常被使用到。我们的常规做法是定义一个ContentProvider,然后在使用的时候使用ContentResolver提供的接口来访问数据。一个进程可以访问自己定义的ContentProvider,也可以访问其他进程定义的ContentProvider。

1.1 继承关系图

1.2 类简介

1.2.1 ContentProvider

ContentProvider作为Android四大组件之一,并没有Activity那样复杂的生命周期,只有简单地onCreate过程。ContentProvider是一个抽象类,当实现自己的ContentProvider类,只需继承于ContentProvider,并且实现以下六个abstract方法即可:

insert(Uri, ContentValues):插入新数据;
delete(Uri, String, String[]):删除已有数据;
update(Uri, ContentValues, String, String[]):更新数据;
query(Uri, String[], String, String[], String):查询数据;
onCreate():执行初始化工作;
getType(Uri):获取数据MIME类型。

1.2.2?ContentResolver

其他app或者进程想要操作ContentProvider,则需要先获取其相应的ContentResolver,再利用ContentResolver类来完成对数据的增删改查操作。

ContextImpl.java

@Override
public ContentResolver getContentResolver() {
    return mContentResolver;
}

1.2.3?ContentProviderHolder

ContentProviderHolder主要是承载ContentProvider的信息和ContentProvider接口内容,并在SystemServer和App进程间传递。

public class ContentProviderHolder implements Parcelable {
    ...
    //描述该ContentProvider的信息
    public final ProviderInfo info;
    //描述该ContentProvider对应的ContentProvider接口,它是一个Binder代理对象
    public IContentProvider provider;
    public IBinder connection;
    public boolean noReleaseNeeded;
}

1.2.4?ContentProviderRecord

一个表示应用层定义的ContentProvider的数据结构,在Framework中可以理解为一个ContentProviderRecord对应应用层中的一个ContentProvider。

final class ContentProviderRecord implements ComponentName.WithComponentName {
    final ActivityManagerService service;
    //描述该ContentProvider的具体信息
    public final ProviderInfo info;
    final int uid;
    //描述定义该ContentProvider的应用的信息
    final ApplicationInfo appInfo;
    //描述标识该ContentProvider的ComponentName
    final ComponentName name;
    //表示该ContentProvider是否是跨用户单例的
    //所谓跨用户单例即系统中只会保存一个这样的ContentProviderRecord结构,多个用户使用的是同一个ContentProviderRecord
    //当第三方应用的ContentProvider想要定义为跨用户单例时,需要添加INTERACT_ACROSS_USERS权限
    final boolean singleton;
    public IContentProvider provider;
    public boolean noReleaseNeeded;
    // All attached clients
    //保存访问该ContentProvider的客户端的连接,用于在比如当前ContentProvider所在进程挂掉等时刻通知客户端进程
    //因为一个ContentProvider定义后可以被系统中不同的进程访问,所以此处使用一个容器来存储
    final ArrayList<ContentProviderConnection> connections
            = new ArrayList<ContentProviderConnection>();
    //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
    // Handles for non-framework processes supported by this provider
    HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
    // Count for external process for which we have no handles.
    int externalProcessNoHandleCount;
    ProcessRecord proc; // if non-null, hosting process.
    ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
    String stringName;
    String shortStringName;
    ...
}

1.2.5?ProviderInfo?

真正描述应用层定义的ContentProvider的属性信息,该结构中基本就是保存定义ContentProvider时声明的各个属性,PMS去扫描AndroidManifest文件时得到的也是该结构。

/**
* Holds information about a specific
* {@link android.content.ContentProvider content provider}. This is returned by
* {@link android.content.pm.PackageManager#resolveContentProvider(java.lang.String, int)
* PackageManager.resolveContentProvider()}.
*/
public final class ProviderInfo extends ComponentInfo implements Parcelable {

    /** The name provider is published under content:// */
    //定义ContentProvider时指定的authority
    public String authority = null;

    /** Optional permission required for read-only access this content
     * provider. */
    //定义ContentProvider时指定的readPermission
    public String readPermission = null;

    /** Optional permission required for read/write access this content
     * provider. */
    //定义ContentProvider时指定的writePermission
    public String writePermission = null;

    /** If true, additional permissions to specific Uris in this content
     * provider can be granted, as per the
     * {@link android.R.styleable#AndroidManifestProvider_grantUriPermissions
     * grantUriPermissions} attribute.
     */
    //定义ContentProvider时指定的grantUriPermissions
    public boolean grantUriPermissions = false;
    ...
}

1.2.6??ContentProviderConnection?

表示一个访问ContentProvider的客户端连接。该结构主要是用于描述一个访问ContentProvider的客户端连接,并保存了客户端在访问ContentProvider时的一些属性。系统中运行的一个ContentProvider是可能被多个客户端访问的,系统就用该结构来记录一个客户端到它访问的ContentProvider之间的连接。

/**
* Represents a link between a content provider and client.
*/
public final class ContentProviderConnection extends Binder {
    //描述其访问的是哪个ContentProvider
    public final ContentProviderRecord provider;
    //描述该客户端进程
    public final ProcessRecord client;
    public final long createTime;
    //用来记录稳定连接的数量
    public int stableCount;
    //用来记录非稳定连接的数量
    public int unstableCount;
    // 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;

    // For debugging.
    public int numStableIncs;
    public int numUnstableIncs;
    ...
}

stableCount、unstableCount 这两个连接数来帮助系统判断当前的ContentProvider还有没有客户端在访问。站在系统的角度看稳定连接与非稳定连接的区别主要是:在ContentProvider发生一些事件时,采用两种不同的连接访问该ContentProvider的客户端会被不同的策略处理。比如当ContentProvider所在的进程挂掉时,系统会遍历该ContentProviderRecord的connections,处理正在访问该ContentProvider的客户端,如果此时客户端采用稳定连接访问,那么系统会连同该客户端一起kill。如果此时客户端采用非稳定连接访问,则系统只是通知客户端访问的ContentProvider已经死亡。那么具体什么时候是稳定连接,什么时候是非稳定连接。这取决于访问数据的方式,一般来说,查询数据会使用非稳定的连接,而增删改则使用的是稳定的连接。

1.2.7?ProviderMap

ProviderMap是服务于AMS的一个类,主要负责管理ContentProviderRecord。

/**
* Keeps track of content providers by authority (name) and class. It separates the mapping by
* user and ones that are not user-specific (system providers).
*/
public final class ProviderMap {

    private static final String TAG = "ProviderMap";
    private static final boolean DBG = false;
    private final ActivityManagerService mAm;
    private final HashMap<String, ContentProviderRecord> mSingletonByName
            = new HashMap<String, ContentProviderRecord>();
    private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass
            = new HashMap<ComponentName, ContentProviderRecord>();
    private final SparseArray<HashMap<String, ContentProviderRecord>> mProvidersByNamePerUser
            = new SparseArray<HashMap<String, ContentProviderRecord>>();
    private final SparseArray<HashMap<ComponentName, ContentProviderRecord>> mProvidersByClassPerUser
            = new SparseArray<HashMap<ComponentName, ContentProviderRecord>>();
    ...
}

1.3 大致流程

假设App B定义了一个ContentProvider,App A需要访问该ContentProvider。整个调用过程简单梳理会经过以下几个步骤:
(1) App A先向SystemServer查询要访问的ContentProvider接口
(2) SystemServer将查询到的ContentProvider接口返回给App ,该ContentProvider接口是定义在App B中的ContentProvider的Binder代理
(3) App A再通过该Binder代理调用定义在App B中的ContentProvider的逻辑

1.4?本地缓存

ActivityThread内部会缓存当前进程已经访问过的ContentProvider或者是当前进程内自己定义的ContentProvider。缓存在其成员变量mProviderMap中。这里注意,在AMS中也有个同名的成员变量mProviderMap,可以大致理解为他们都用来缓存ContentProvider接口,只不过一个是在本地进程中缓存,一个是在SystemServer中全局缓存。

1.5 整体流程图

二、源码分析

?2.1 getContentResolver

Context中调用getContentResolver,经过层层调用来到ContextImpl类。返回值mContentResolver赋值是在ContextImpl对象创建过程完成赋值。

class ContextImpl extends Context {
    public ContentResolver getContentResolver() {
        return mContentResolver;
    }

    private ContextImpl(...) {
        ...
        mContentResolver = new ApplicationContentResolver(this, mainThread);
    }
}

2.2 ContentResolver.query

public abstract class ContentResolver {
    ...
    public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
            @Nullable String[] projection, @Nullable Bundle queryArgs,
            @Nullable CancellationSignal cancellationSignal) {
        Preconditions.checkNotNull(uri, "uri");
        IContentProvider unstableProvider = acquireUnstableProvider(uri);
        ...
        IContentProvider stableProvider = null;
        Cursor qCursor = null;
        try {
            ...
            try {
                qCursor = unstableProvider.query(mPackageName, uri, projection,
                        queryArgs, remoteCancellationSignal);
            } catch (DeadObjectException e) {
                // The remote process has died...  but we only hold an unstable
                // reference though, so we might recover!!!  Let's try!!!!
                // This is exciting!!1!!1!!!!1
                // 远程进程死亡,处理unstable provider死亡过程
                unstableProviderDied(unstableProvider);
                //unstable类型死亡后,再创建stable类型的provider
                stableProvider = acquireProvider(uri);
                if (stableProvider == null) {
                    return null;
                }
                qCursor = stableProvider.query(
                        mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
            }
            if (qCursor == null) {
                return null;
            }

            // Force query execution.  Might fail and throw a runtime exception here.
            qCursor.getCount();
            long durationMillis = SystemClock.uptimeMillis() - startTime;
            maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);

            // Wrap the cursor object into CursorWrapperInner object.
            //创建对象CursorWrapperInner
            final IContentProvider provider = (stableProvider != null) ? stableProvider
                    : acquireProvider(uri);
            final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
            stableProvider = null;
            qCursor = null;
            return wrapper;
        } catch (RemoteException e) {
            // Arbitrary and not worth documenting, as Activity
            // Manager will kill this process shortly anyway.
            return null;
        } finally {
            if (qCursor != null) {
                qCursor.close();
            }
            if (cancellationSignal != null) {
                cancellationSignal.setRemote(null);
            }
            if (unstableProvider != null) {
                releaseUnstableProvider(unstableProvider);
            }
            if (stableProvider != null) {
                releaseProvider(stableProvider);
            }
        }
    }
    ...
}

一般地获取unstable的provider:

(1) 调用acquireUnstableProvider(),尝试获取unstable的ContentProvider
(2) 然后执行query操作
(3) 当执行query过程抛出DeadObjectException,即代表ContentProvider所在进程死亡,则尝试获取stable的ContentProvider

(4) 先调用unstableProviderDied(), 清理刚创建的unstable的ContentProvider
(5) 调用acquireProvider(),尝试获取stable的ContentProvider; 此时当ContentProvider进程死亡,则会杀掉该ContentProvider的客户端进程
(6) 然后执行query操作

stable与unstable的区别:采用unstable类型的ContentProvider的app不会因为远程ContentProvider进程的死亡而被杀,stable则恰恰相反。这便是ContentProvider坑爹之处,对于app无法事先决定创建的ContentProvider是stable,还是unstable 类型的,也便无法得知自己的进程是否会依赖于远程ContentProvider的生死。

2.3?ContentResolver.acquireUnstableProvider

public abstract class ContentResolver {
    ...
    /**
    * Returns the content provider for the given content URI.
    *
    * @param uri The URI to a content provider
    * @return The ContentProvider for the given URI, or null if no content provider is found.
    * @hide
    */
    public final IContentProvider acquireUnstableProvider(Uri uri) {
        if (!SCHEME_CONTENT.equals(uri.getScheme())) {
            return null;
        }
        String auth = uri.getAuthority();
        if (auth != null) {
            return acquireUnstableProvider(mContext, uri.getAuthority());
        }
        return null;
    }
    ...
}
class ContextImpl extends Context {
    ...
    private static final class ApplicationContentResolver extends ContentResolver {
        private final ActivityThread mMainThread;

        public ApplicationContentResolver(Context context, ActivityThread mainThread) {
            super(context);
            mMainThread = Preconditions.checkNotNull(mainThread);
        }

        @Override
        protected IContentProvider acquireProvider(Context context, String auth) {
            return mMainThread.acquireProvider(context,
                    ContentProvider.getAuthorityWithoutUserId(auth),
                    resolveUserIdFromAuthority(auth), true);
        }

        @Override
        protected IContentProvider acquireExistingProvider(Context context, String auth) {
            return mMainThread.acquireExistingProvider(context,
                    ContentProvider.getAuthorityWithoutUserId(auth),
                    resolveUserIdFromAuthority(auth), true);
        }

        @Override
        public boolean releaseProvider(IContentProvider provider) {
            return mMainThread.releaseProvider(provider, true);
        }

        @Override
        protected IContentProvider acquireUnstableProvider(Context c, String auth) {
            return mMainThread.acquireProvider(c,
                    ContentProvider.getAuthorityWithoutUserId(auth),
                    resolveUserIdFromAuthority(auth), false);
        }

        @Override
        public boolean releaseUnstableProvider(IContentProvider icp) {
            return mMainThread.releaseProvider(icp, false);
        }

        @Override
        public void unstableProviderDied(IContentProvider icp) {
            mMainThread.handleUnstableProviderDied(icp.asBinder(), true);
        }

        @Override
        public void appNotRespondingViaProvider(IContentProvider icp) {
            mMainThread.appNotRespondingViaProvider(icp.asBinder());
        }

        /** @hide */
        protected int resolveUserIdFromAuthority(String auth) {
            return ContentProvider.getUserIdFromAuthority(auth, getUserId());
        }
    }
    ...
}
public final class ActivityThread extends ClientTransactionHandler {
    ...
    public final IContentProvider acquireProvider(
            Context c, String auth, int userId, boolean stable) {
        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
        if (provider != null) {
            //成功获取已经存在的ContentProvider对象,则直接返回
            return provider;
        }

        // There is a possible race here.  Another thread may try to acquire
        // the same provider at the same time.  When this happens, we want to ensure
        // that the first one wins.
        // Note that we cannot hold the lock while acquiring and installing the
        // provider since it might take a long time to run and it could also potentially
        // be re-entrant in the case where the provider is in the same process.
        ContentProviderHolder holder = null;
        try {
            synchronized (getGetProviderLock(auth, userId)) {
                holder = ActivityManager.getService().getContentProvider(
                        getApplicationThread(), auth, userId, stable);
            }
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        //无法获取auth所对应的provider则直接返回
        if (holder == null) {
            Slog.e(TAG, "Failed to find provider info for " + auth);
            return null;
        }

        // Install provider will increment the reference count for us, and break
        // any ties in the race.
        //安装provider将会增加引用计数
        holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
        return holder.provider;
    }
    ...
}

不论是acquireUnstableProvider还是acquireProvider方法,最终都会调用ActivityThread的同一个方法acquireProvider()。该方法的主要功能:

(1) 首先,尝试获取已存储的provider,当成功获取则直接返回,否则继续执行
(2) 通过AMS来获取provider,当无法获取auth所对应的provider则直接返回,否则继续执行
(3) 采用installProvider安装provider,并该provider的增加引用计数

2.4?ActivityThread.acquireExistingProvider

public final class ActivityThread extends ClientTransactionHandler {
    ...
    public final IContentProvider acquireExistingProvider(
            Context c, String auth, int userId, boolean stable) {
        synchronized (mProviderMap) {
            final ProviderKey key = new ProviderKey(auth, userId);
            //从AT.mProviderMap查询是否存在相对应的provider
            final ProviderClientRecord pr = mProviderMap.get(key);
            if (pr == null) {
                return null;
            }

            IContentProvider provider = pr.mProvider;
            IBinder jBinder = provider.asBinder();
            if (!jBinder.isBinderAlive()) {
                // The hosting process of the provider has died; we can't
                // use this one.
                Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
                        + ": existing object's process dead");
                //当provider所在进程已经死亡则返回
                handleUnstableProviderDiedLocked(jBinder, true);
                return null;
            }

            // Only increment the ref count if we have one.  If we don't then the
            // provider is not reference counted and never needs to be released.
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
            if (prc != null) {
                //增加引用计数
                incProviderRefLocked(prc, stable);
            }
            return provider;
        }
    }
    ...
}

(1) 首先从ActivityThread的mProviderMap查询是否存在相对应的provider,若不存在则直接返回
(2) 当provider记录存在,但其所在进程已经死亡,则调用handleUnstableProviderDiedLocked清理provider信息,并返回
(3) 当provider记录存在,且进程存活的情况下,则在provider引用计数不为空时则继续增加引用计数

2.5?AMS.getContentProvider

public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ...
    @Override
    public final ContentProviderHolder getContentProvider(
            IApplicationThread caller, String name, int userId, boolean stable) {
        enforceNotIsolatedCaller("getContentProvider");
        if (caller == null) {
            String msg = "null IApplicationThread when getting content provider "
                    + name;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }
        // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
        // with cross-user grant.
        //此处name就是前面的auth,对应于AndroidManifest.xml中provider标签里面的android:authorities的值
        return getContentProviderImpl(caller, name, null, stable, userId);
    }

    private 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.uptimeMillis();
    
            ProcessRecord r = null;
            if (caller != null) {
                //获取调用者的进程记录ProcessRecord
                r = getRecordForAppLocked(caller);
                ...
            }
            ...
            // First check if this content provider has been published...
            //从AMS中查询相应的ContentProviderRecord
            cpr = mProviderMap.getProviderByName(name, userId);
            // If that didn't work, check if it exists for user 0 and then
            // verify that it's a singleton provider before using it.
            if (cpr == null && userId != UserHandle.USER_SYSTEM) {
                cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
                if (cpr != null) {
                    cpi = cpr.info;
                    if (isSingleton(cpi.processName, cpi.applicationInfo,
                            cpi.name, cpi.flags)
                            && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
                        userId = UserHandle.USER_SYSTEM;
                        checkCrossUser = false;
                    } else {
                        cpr = null;
                        cpi = null;
                    }
                }
            }
    
            boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
            // 目标provider已存在的情况
            if (providerRunning) {
                ...
            }

            // 目标provider不存在的情况
            if (!providerRunning) {
                ...
            }
            ...
        }
    
        // Wait for the provider to be published...
        //循环等待provider发布完成
        synchronized (cpr) {
            while (cpr.provider == null) {
                ...
            }
        }
        return cpr != null ? cpr.newHolder(conn) : null;
    }
    ...
}

该方法比较长,也是获取provider的核心实现代码,这里分成以下3部分:

(1) 目标provider已存在的情况
(2) 目标provider不存在的情况
(3) 循环等待provider发布完成

2.5.1?目标provider已存在

private 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.uptimeMillis();

        ProcessRecord r = null;
        if (caller != null) {
            //获取调用者的进程记录ProcessRecord
            r = getRecordForAppLocked(caller);
            ...
        }
        ...
        // First check if this content provider has been published...
        //从AMS中查询相应的ContentProviderRecord
        cpr = mProviderMap.getProviderByName(name, userId);
        // If that didn't work, check if it exists for user 0 and then
        // verify that it's a singleton provider before using it.
        if (cpr == null && userId != UserHandle.USER_SYSTEM) {
            cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
            if (cpr != null) {
                cpi = cpr.info;
                if (isSingleton(cpi.processName, cpi.applicationInfo,
                        cpi.name, cpi.flags)
                        && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
                    userId = UserHandle.USER_SYSTEM;
                    checkCrossUser = false;
                } else {
                    cpr = null;
                    cpi = null;
                }
            }
        }

        boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
        // 目标provider已存在的情况
        if (providerRunning) {
            cpi = cpr.info;
            String msg;
            ...
            //当允许运行在调用者进程且已发布,则直接返回
            if (r != null && cpr.canRunHere(r)) {
                // This provider has been published or is in the process
                // of being published...  but it is also allowed to run
                // in the caller's process, so don't make a connection
                // and just let the caller instantiate its own instance.
                ContentProviderHolder holder = cpr.newHolder(null);
                // don't give caller the provider object, it needs
                // to make its own.
                holder.provider = null;
                return holder;
            }
            // Don't expose providers between normal apps and instant apps
            try {
                if (AppGlobals.getPackageManager()
                        .resolveContentProvider(name, 0 /*flags*/, userId) == null) {
                    return null;
                }
            } catch (RemoteException e) {
            }

            final long origId = Binder.clearCallingIdentity();
            ...
            // In this case the provider instance already exists, so we can
            // return it right away.
            //增加引用计数
            conn = incProviderCountLocked(r, cpr, token, stable);
            if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
                if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                    // If this is a perceptible app accessing the provider,
                    // make sure to count it as being accessed and thus
                    // back up on the LRU list.  This is good because
                    // content providers are often expensive to start.
                    checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
                    //更新进程LRU队列
                    updateLruProcessLocked(cpr.proc, false, null);
                    checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
                }
            }

            checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
            final int verifiedAdj = cpr.proc.verifiedAdj;
            boolean success = updateOomAdjLocked(cpr.proc, true);
            // XXX things have changed so updateOomAdjLocked doesn't actually tell us
            // if the process has been successfully adjusted.  So to reduce races with
            // it, we will check whether the process still exists.  Note that this doesn't
            // completely get rid of races with LMK killing the process, but should make
            // them much smaller.
            if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
                success = false;
            }
            maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
            checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
            if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
            // NOTE: there is still a race here where a signal could be
            // pending on the process even though we managed to update its
            // adj level.  Not sure what to do about this, but at least
            // the race is now smaller.
            if (!success) {
                // Uh oh...  it looks like the provider's process
                // has been killed on us.  We need to wait for a new
                // process to be started, and make sure its death
                // doesn't kill our process.
                Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
                        + " is crashing; detaching " + r);
                //provider进程被杀,则减少引用计数
                boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
                checkTime(startTime, "getContentProviderImpl: before appDied");
                appDiedLocked(cpr.proc);
                checkTime(startTime, "getContentProviderImpl: after appDied");
                if (!lastRef) {
                    // This wasn't the last ref our process had on
                    // the provider...  we have now been killed, bail.
                    return null;
                }
                providerRunning = false;
                conn = null;
            } else {
                cpr.proc.verifiedAdj = cpr.proc.setAdj;
            }

            Binder.restoreCallingIdentity(origId);
        }
    }
    ...
}

当ContentProvider所在进程已存在时的功能:

(1) 权限检查
(2) 当允许运行在调用者进程且已发布,则直接返回
(3) 增加引用计数
(4) 更新进程LRU队列
(5) 更新进程adj
(6) 当provider进程被杀时,则减少引用计数并调用appDiedLocked,且设置ContentProvider为没有发布的状态

2.5.2?目标provider不存在

private 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.uptimeMillis();

        ProcessRecord r = null;
        if (caller != null) {
            //获取调用者的进程记录ProcessRecord
            r = getRecordForAppLocked(caller);
            ...
        }
        ...
        // First check if this content provider has been published...
        //从AMS中查询相应的ContentProviderRecord
        cpr = mProviderMap.getProviderByName(name, userId);
        // If that didn't work, check if it exists for user 0 and then
        // verify that it's a singleton provider before using it.
        if (cpr == null && userId != UserHandle.USER_SYSTEM) {
            cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
            if (cpr != null) {
                cpi = cpr.info;
                if (isSingleton(cpi.processName, cpi.applicationInfo,
                        cpi.name, cpi.flags)
                        && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
                    userId = UserHandle.USER_SYSTEM;
                    checkCrossUser = false;
                } else {
                    cpr = null;
                    cpi = null;
                }
            }
        }

        boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
       // 目标provider不存在的情况
       if (!providerRunning) {
           try {
               checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
               //根据authority,获取ProviderInfo对象
               cpi = AppGlobals.getPackageManager().
                   resolveContentProvider(name,
                       STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
               checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
           } catch (RemoteException ex) {
           }
           if (cpi == null) {
               return null;
           }
           // If the provider is a singleton AND
           // (it's a call within the same user || the provider is a
           // privileged app)
           // Then allow connecting to the singleton provider
           boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                   cpi.name, cpi.flags)
                   && isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
           if (singleton) {
               userId = UserHandle.USER_SYSTEM;
           }
           cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
           checkTime(startTime, "getContentProviderImpl: got app info for user");

           String msg;
           checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
           if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
                   != null) {
               throw new SecurityException(msg);
           }
           checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
           ...
           ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
           checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
           cpr = mProviderMap.getProviderByClass(comp, userId);
           checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
           final boolean firstClass = cpr == null;
           if (firstClass) {
               final long ident = Binder.clearCallingIdentity();

               // If permissions need a review before any of the app components can run,
               // we return no provider and launch a review activity if the calling app
               // is in the foreground.
               if (mPermissionReviewRequired) {
                   if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) {
                       return null;
                   }
               }

               try {
                   checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
                   ApplicationInfo ai =
                       AppGlobals.getPackageManager().
                           getApplicationInfo(
                                   cpi.applicationInfo.packageName,
                                   STOCK_PM_FLAGS, userId);
                   checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
                   if (ai == null) {
                       Slog.w(TAG, "No package info for content provider "
                               + cpi.name);
                       return null;
                   }
                   ai = getAppInfoForUser(ai, userId);
                   //创建对象ContentProviderRecord
                   cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
               } catch (RemoteException ex) {
                   // pm is in same process, this will never happen.
               } finally {
                   Binder.restoreCallingIdentity(ident);
               }
           }

           checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");

           if (r != null && cpr.canRunHere(r)) {
               // If this is a multiprocess provider, then just return its
               // info and allow the caller to instantiate it.  Only do
               // this if the provider is the same user as the caller's
               // process, or can run as root (so can be in any process).
               return cpr.newHolder(null);
           }

           // This is single process, and our app is now connecting to it.
           // See if we are already in the process of launching this
           // provider.
           final int N = mLaunchingProviders.size();
           int i;
           //从mLaunchingProviders中查询是否存在该cpr
           for (i = 0; i < N; i++) {
               if (mLaunchingProviders.get(i) == cpr) {
                   break;
               }
           }

           // If the provider is not already being launched, then get it
           // started.
           //当provider并没有处于mLaunchingProviders队列,则启动它
           if (i >= N) {
               final long origId = Binder.clearCallingIdentity();

               try {
                   // Content provider is now in use, its package can't be stopped.
                   try {
                       checkTime(startTime, "getContentProviderImpl: before set stopped state");
                       AppGlobals.getPackageManager().setPackageStoppedState(
                               cpr.appInfo.packageName, false, userId);
                       checkTime(startTime, "getContentProviderImpl: after set stopped state");
                   } catch (RemoteException e) {
                   } catch (IllegalArgumentException e) {
                       Slog.w(TAG, "Failed trying to unstop package "
                               + cpr.appInfo.packageName + ": " + e);
                   }

                   // Use existing process if already started
                   checkTime(startTime, "getContentProviderImpl: looking for process record");
                   //查询进程记录ProcessRecord
                   ProcessRecord proc = getProcessRecordLocked(
                           cpi.processName, cpr.appInfo.uid, false);
                   if (proc != null && proc.thread != null && !proc.killed) {
                       if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
                               "Installing in existing process " + proc);
                       if (!proc.pubProviders.containsKey(cpi.name)) {
                           checkTime(startTime, "getContentProviderImpl: scheduling install");
                           proc.pubProviders.put(cpi.name, cpr);
                           try {
                               //启动provider进程启动并发布provider
                               proc.thread.scheduleInstallProvider(cpi);
                           } catch (RemoteException e) {
                           }
                       }
                   } else {
                       checkTime(startTime, "getContentProviderImpl: before start process");
                       // 启动进程
                       proc = startProcessLocked(cpi.processName,
                               cpr.appInfo, false, 0, "content provider",
                               new ComponentName(cpi.applicationInfo.packageName,
                                       cpi.name), false, false, false);
                       checkTime(startTime, "getContentProviderImpl: after start process");
                       if (proc == null) {
                           Slog.w(TAG, "Unable to launch app "
                                   + cpi.applicationInfo.packageName + "/"
                                   + cpi.applicationInfo.uid + " for provider "
                                   + name + ": process is bad");
                           return null;
                       }
                   }
                   cpr.launchingApp = proc;
                   //将cpr添加到mLaunchingProviders
                   mLaunchingProviders.add(cpr);
               } finally {
                   Binder.restoreCallingIdentity(origId);
               }
           }

           checkTime(startTime, "getContentProviderImpl: updating data structures");

           // Make sure the provider is published (the same provider class
           // may be published under multiple names).
           if (firstClass) {
               mProviderMap.putProviderByClass(comp, cpr);
           }
           //增加引用计数
           mProviderMap.putProviderByName(name, cpr);
           conn = incProviderCountLocked(r, cpr, token, stable);
           if (conn != null) {
               conn.waiting = true;
           }
       }
    }
    ...
}

当ContentProvider所在进程没有存在时的功能:

(1) 根据authority,获取ProviderInfo对象
(2) 权限检查
(3) 当provider不是运行在system进程,且系统未准备好,则抛出IllegalArgumentException
(4) 当拥有该provider的用户并没有运行,则直接返回
(5) 根据ComponentName,从AMS.mProviderMap中查询相应的ContentProviderRecord
(6) 当首次调用,则创建对象ContentProviderRecord
(7) 当允许运行在调用者进程且ProcessRecord不为空,则直接返回
(8) 当provider并没有处于mLaunchingProviders队列,则启动它
(9) 当ProcessRecord不为空,则加入到pubProviders,并开始安装provider
(10) 当ProcessRecord为空,则启动进程
(11) 增加引用计数

2.5.3?等待目标provider发布

private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
        String name, IBinder token, boolean stable, int userId) {
    ContentProviderRecord cpr;
    ContentProviderConnection conn = null;
    ProviderInfo cpi = null;

    synchronized(this) {
        ...
        // Wait for the provider to be published...
        //循环等待provider发布完成
        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;
    }
    ...
}

循环等待,直到provider发布完成才会退出循环。

一般地, 程序进行到此处, AT.acquireProvider方法应该已成功获取了Provider对象, 接下来便是安装Provider。通过调用installContentProviders()方法本地安装ContentProvider,这里可以简单理解所谓本地安装就是填充ActivityThread中保存ContentProvider接口的缓存,但是要注意当前的ActivityThread是表示定义ContentProvider的进程(App B),而不是使用ContentProvider的进程(App A)。

2.6?AT.installProvider

public final class ActivityThread extends ClientTransactionHandler {
    ...
    /**
    * Installs the provider.
    *
    * Providers that are local to the process or that come from the system server
    * may be installed permanently which is indicated by setting noReleaseNeeded to true.
    * Other remote providers are reference counted.  The initial reference count
    * for all reference counted providers is one.  Providers that are not reference
    * counted do not have a reference count (at all).
    *
    * This method detects when a provider has already been installed.  When this happens,
    * it increments the reference count of the existing provider (if appropriate)
    * and returns the existing provider.  This can happen due to concurrent
    * attempts to acquire the same provider.
    */
    private ContentProviderHolder installProvider(Context context,
            ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {
        ContentProvider localProvider = null;
        IContentProvider provider;
        if (holder == null || holder.provider == null) {
            ...
        } else {
            provider = holder.provider;
        }
    
        ContentProviderHolder retHolder;
    
        synchronized (mProviderMap) {
            IBinder jBinder = provider.asBinder();
            if (localProvider != null) {
                ComponentName cname = new ComponentName(info.packageName, info.name);
                ProviderClientRecord pr = mLocalProvidersByName.get(cname);
                if (pr != null) {
                    if (DEBUG_PROVIDER) {
                        Slog.v(TAG, "installProvider: lost the race, "
                                + "using existing local provider");
                    }
                    provider = pr.mProvider;
                } else {
                    holder = new ContentProviderHolder(info);
                    holder.provider = provider;
                    holder.noReleaseNeeded = true;
                    pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                    mLocalProviders.put(jBinder, pr);
                    mLocalProvidersByName.put(cname, pr);
                }
                retHolder = pr.mHolder;
            } else {
                //根据jBinder,从mProviderRefCountMap中查询相应的ProviderRefCount
                ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
                if (prc != null) {
                    if (DEBUG_PROVIDER) {
                        Slog.v(TAG, "installProvider: lost the race, updating ref count");
                    }
                    // We need to transfer our new reference to the existing
                    // ref count, releasing the old one...  but only if
                    // release is needed (that is, it is not running in the
                    // system process).
                    //只有当需要释放引用时则进入该分支
                    if (!noReleaseNeeded) {
                        incProviderRefLocked(prc, stable);
                        try {
                            ActivityManager.getService().removeContentProvider(
                                    holder.connection, stable);
                        } catch (RemoteException e) {
                            //do nothing content provider object is dead any way
                        }
                    }
                } else {
                    ProviderClientRecord client = installProviderAuthoritiesLocked(
                            provider, localProvider, holder);
                    if (noReleaseNeeded) {
                        prc = new ProviderRefCount(holder, client, 1000, 1000);
                    } else {
                        prc = stable
                                ? new ProviderRefCount(holder, client, 1, 0)
                                : new ProviderRefCount(holder, client, 0, 1);
                    }
                    mProviderRefCountMap.put(jBinder, prc);
                }
                retHolder = prc.holder;
            }
        }
        return retHolder;
    }
    ...
    private static final class ProviderRefCount {
        public final ContentProviderHolder holder;
        public final ProviderClientRecord client;
        public int stableCount;
        public int unstableCount;
        ...
    }
}

获取ContentProviderHolder对象,该对象的成员变量provider记录着ContentProviderProxy对象。

2.6.1?AMS.removeContentProvider

public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ...
    public void removeContentProvider(IBinder connection, boolean stable) {
        enforceNotIsolatedCaller("removeContentProvider");
        long ident = Binder.clearCallingIdentity();
        try {
            synchronized (this) {
                ContentProviderConnection conn;
                try {
                    conn = (ContentProviderConnection)connection;
                } catch (ClassCastException e) {
                    ...
                }
                if (conn == null) {
                    throw new NullPointerException("connection is null");
                }
                if (decProviderCountLocked(conn, null, null, stable)) {
                    updateOomAdjLocked();
                }
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    boolean decProviderCountLocked(ContentProviderConnection conn,
            ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
        if (conn != null) {
            cpr = conn.provider;

            if (stable) {
                conn.stableCount--;
            } else {
                conn.unstableCount--;
            }
            //当provider连接的 stable和unstable引用次数都为0时,则移除该连接对象信息
            if (conn.stableCount == 0 && conn.unstableCount == 0) {
                cpr.connections.remove(conn);
                conn.client.conProviders.remove(conn);
                if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
                    // The client is more important than last activity -- note the time this
                    // is happening, so we keep the old provider process around a bit as last
                    // activity to avoid thrashing it.
                    if (cpr.proc != null) {
                        cpr.proc.lastProviderTime = SystemClock.uptimeMillis();
                    }
                }
                stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, cpr.name);
                return true;
            }
            return false;
        }
        cpr.removeExternalProcessHandleLocked(externalProcessToken);
        return false;
    }
    ...
}

2.7?CPP.query?

执行完acquireUnstableProvider()操作则成功获取了ContentProviderProxy

abstract public class ContentProviderNative extends Binder implements IContentProvider {
    ...
    final class ContentProviderProxy implements IContentProvider {
        ...
    }
    ...
}
abstract public class ContentProviderNative extends Binder implements IContentProvider {
    ...
    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        try {
            switch (code) {
                case QUERY_TRANSACTION:
                {
                    data.enforceInterface(IContentProvider.descriptor);
 
                    String callingPkg = data.readString();
                    Uri url = Uri.CREATOR.createFromParcel(data);
 
                    // String[] projection
                    int num = data.readInt();
                    String[] projection = null;
                    if (num > 0) {
                        projection = new String[num];
                        for (int i = 0; i < num; i++) {
                            projection[i] = data.readString();
                        }
                    }
 
                    Bundle queryArgs = data.readBundle();
                    IContentObserver observer = IContentObserver.Stub.asInterface(
                            data.readStrongBinder());
                    ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
                             data.readStrongBinder());
 
                     Cursor cursor = query(callingPkg, url, projection, queryArgs, 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 {
                             // Close cursor if an exception was thrown while constructing the adaptor.
                             if (adaptor != null) {
                                 adaptor.close();
                             }
                             if (cursor != null) {
                                 cursor.close();
                             }
                         }
                     } else {
                         reply.writeNoException();
                         reply.writeInt(0);
                     }
 
                     return true;
                }
                ...
            }
        }
    }
    
    final class ContentProviderProxy implements IContentProvider {
        ...
        @Override
        public Cursor query(String callingPkg, Uri url, @Nullable String[] projection,
                @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
                throws RemoteException {
            BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            try {
                data.writeInterfaceToken(IContentProvider.descriptor);
    
                data.writeString(callingPkg);
                url.writeToParcel(data, 0);
                int length = 0;
                if (projection != null) {
                    length = projection.length;
                }
                data.writeInt(length);
                for (int i = 0; i < length; i++) {
                    data.writeString(projection[i]);
                }
                data.writeBundle(queryArgs);
                data.writeStrongBinder(adaptor.getObserver().asBinder());
                data.writeStrongBinder(
                        cancellationSignal != null ? cancellationSignal.asBinder() : null);
                //发送给Binder服务端
                mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
    
                DatabaseUtils.readExceptionFromParcel(reply);
    
                if (reply.readInt() != 0) {
                    BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
                    Binder.copyAllowBlocking(mRemote, (d.cursor != null) ? d.cursor.asBinder() : null);
                    adaptor.initialize(d);
                } else {
                    adaptor.close();
                    adaptor = null;
                }
                return adaptor;
            } catch (RemoteException ex) {
                adaptor.close();
                throw ex;
            } catch (RuntimeException ex) {
                adaptor.close();
                throw ex;
            } finally {
                data.recycle();
                reply.recycle();
            }
        }
        ...
    }
    ...
}

到这里通过跨进程的方式,真正调用到了目标provider的query方法。

三、Provider 进程

3.1 两种场景

发布ContentProvider分两种情况:Provider进程尚未启动,Provider进程已启动但未发布。

场景一(Provider进程尚未启动):system_server进程调用startProcessLocked()创建provider进程且attach到system_server后,通过binder call到provider进程执行AT.bindApplication()方法 。

场景二(Provider进程已启动但未发布): provider进程已存在且attach到system_server,但所对应的provider还没有发布,通过binder call到provider进程执行AT.scheduleInstallProvider方法。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-04 11:09:00  更:2022-02-04 11:11:41 
 
开发: 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 14:04:41-

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