ContentProvider使用与query流程分析

涉及文件:

frameworks\base\core\java\android\content\pm\PackageParser.java

frameworks\base\core\java\android\app\ContextImpl.java

frameworks\base\core\java\android\app\ActivityThread.java

frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

frameworks\base\core\java\android\content\ContentResolver.java

frameworks\base\core\java\android\content\ContentProvider.java

contentProvider使用示例:

Manifest文件中定义provider,指定authorities,permission,权限还可以细分为readpermission和writepermission。

<provider
    android:authorities="com.qiku.healthguard.healthdata"
    android:name="com.qiku.healthguard.provide.HealthProvider"
    android:exported="true"
    android:permission="com.qiku.permission.GET_HG_DATA"
    />

新建类继承自ContentProvider,重载query,insert,delete,update四个接口,分别实现数据库的增删改查

public class HealthProvider extends ContentProvider {private final static String TAG = "HealthProvider:";
private DbHelper dbHelper;
private static final UriMatcher matcher;
static {
    matcher = new UriMatcher(UriMatcher.NO_MATCH);
    matcher.addURI(DbConstant.AUTHOR,DbConstant.TB_FATIGUE,DbConstant.CODE_FATIGUE);
    matcher.addURI(DbConstant.AUTHOR,DbConstant.TB_HEALTH_REPORT,DbConstant.CODE_HEALTH_REPORT);
    matcher.addURI(DbConstant.AUTHOR,DbConstant.TB_SLEEP,DbConstant.CODE_SLEEP);
    matcher.addURI(DbConstant.AUTHOR,DbConstant.TB_TIME_SET,DbConstant.CODE_TIME);
    matcher.addURI(DbConstant.AUTHOR,DbConstant.TB_SCREEN,DbConstant.CODE_SCREEN);
}

@Override
public boolean onCreate() {
    dbHelper = new DbHelper(getContext());
    return true;
}

@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                    @Nullable String[] selectionArgs, @Nullable String sortOrder) {
    String table = getType(uri);
    SQLiteDatabase database = dbHelper.getReadableDatabase();
    if(table==null || database==null) {
        return null;
    }
    Cursor cursor = database.query(table,projection,selection,selectionArgs,null,null,sortOrder);
    return cursor;
}

@Nullable
@Override
public String getType(@NonNull Uri uri) {
    String table = null;
    switch (matcher.match(uri)) {
        case DbConstant.CODE_FATIGUE:
            table = DbConstant.TB_FATIGUE;
            break;
        case DbConstant.CODE_HEALTH_REPORT:
            table = DbConstant.TB_HEALTH_REPORT;
            break;
        case DbConstant.CODE_SLEEP:
            table = DbConstant.TB_SLEEP;
            break;
        case DbConstant.CODE_TIME:
            table = DbConstant.TB_TIME_SET;
            break;
        case DbConstant.CODE_SCREEN:
            table = DbConstant.TB_SCREEN;
            break;
        default:
            break;
    }
    return table;
}

@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
    String table  = getType(uri);
    SQLiteDatabase database = dbHelper.getWritableDatabase();
    database.insert(table,null,contentValues);
    return uri;
}

@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
    String table = getType(uri);
    SQLiteDatabase database = dbHelper.getWritableDatabase();
    int i = database.delete(table,selection,selectionArgs);
    return 0;
}

@Override
public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String selection,
                  @Nullable String[] selectionArgs) {
    String table = getType(uri);
    SQLiteDatabase database = dbHelper.getWritableDatabase();
    int i = database.update(table,contentValues,selection,selectionArgs);
    return 0;
}
}

新建类继承自SQLiteOpenHelper,分别实现构造方法和onCreate(完成数据库新建操作)、onUpgrade(完成数据库升级)、onDowngrade(完成数据库的降级)

public class DbHelper extends SQLiteOpenHelper {

    public static String CREATE_FATIGUE="CREATE TABLE IF NOT EXISTS fatigue(" +
            "id INTEGER PRIMARY KEY," +
            "total_s INT DEFAULT 0," +
            "total_m INT DEFAULT 0," +
            "total_mi INT DEFAULT 0," +
            "total_f INT DEFAULT 0," +
            "unlock_s INT DEFAULT 0," +
            "unlock_m INT DEFAULT 0," +
            "unlock_mi INT DEFAULT 0," +
            "unlock_f INT DEFAULT 0," +
            "app_s INT DEFAULT 0," +
            "app_m INT DEFAULT 0," +
            "app_mi INT DEFAULT 0," +
            "app_f INT DEFAULT 0" +
            ");";
    public static final String CREATE_SLEEP = "CREATE TABLE IF NOT EXISTS sleep_data(" +
            "id INTEGER PRIMARY KEY," +
            "start_time INTEGER DEFAULT 0," +
            "end_time INTEGER DEFAULT 0," +
            "sleep_time INTEGER DEFAULT 0," +
            "weekdata VARCHAR(50) DEFAULT NULL," +
            "modify_time LONG);";
    public static final String CREATE_TIME = "CREATE TABLE IF NOT EXISTS time_data(" +
            "id INTEGER PRIMARY KEY," +
            "notice_enable INTEGER DEFAULT 1," +
            "device_oneday LONG DEFAULT 28800000," +
            "device_once LONG DEFAULT 7200000," +
            "app_once LONG DEFAULT 7200000" +
            ");";
    public static final String CREATE_SCREEN = "CREATE TABLE IF NOT EXISTS screen_data(" +
            "id INTEGER PRIMARY KEY," +
            "modify_date LONG," +
            "screen_on LONG," +
            "screen_off LONG," +
            "screen_on_off_duration INTEGER" +
            ");";

    public static final String DROP_FATIGUE = "drop table fatigue";
    public static final String DROP_SLEEP = "drop table sleep_data";
    public static final String DROP_TIME = "drop table time_data";
    public static final String DROP_SCREEN = "drop table screen_table";


    public DbHelper(Context cn) {
        super(cn, DbConstant.DATABASE, null, DbConstant.DB_VERSION);
    }

    public DbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, DbConstant.DATABASE, factory, DbConstant.DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(CREATE_FATIGUE);
        sqLiteDatabase.execSQL(CREATE_SLEEP);
        sqLiteDatabase.execSQL(CREATE_TIME);
        sqLiteDatabase.execSQL(CREATE_SCREEN);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(DROP_FATIGUE);
        db.execSQL(DROP_SLEEP);
        db.execSQL(DROP_TIME);
        onCreate(db);
    }

    @Override
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(DROP_FATIGUE);
        db.execSQL(DROP_SLEEP);
        db.execSQL(DROP_TIME);
        onCreate(db);
    }
}

以上就完成了数据库的准备工作,需要使用数据库时如下调用即可:

ContentResolver cr = context.getContentResolver();
Uri uri = Uri.parse(UriStr);
//uri组成:content://+manifest中定义的authorities+/+数据库表名
Cursor cursor = cr.query(uri,null,null,null,null);
ArrayList<SleepData> list = new ArrayList<>();
if(cursor == null) {
    return list;
}
while(cursor.moveToNext()) {
    SleepData data = new SleepData();
    data.setStartTime(cursor.getInt(cursor.getColumnIndexOrThrow("start_time")));
    data.setEndTime(cursor.getInt(cursor.getColumnIndexOrThrow("end_time")));
    data.setSleepTime(cursor.getInt(cursor.getColumnIndexOrThrow("sleep_time")));
    data.setDate(cursor.getString(cursor.getColumnIndexOrThrow("weekdata")));
    data.setModifyTime(cursor.getLong(cursor.getColumnIndexOrThrow("modify_time")));
    list.add(data);
}

query调用流程如下图:

通过调用contentresolver获得需要读写的数据库的provider的代理对象,获取过程分为当前进程下的和跨进程的获取,如果跨进程,并且对应进程当前并没有在后台中,

则会启动该进程,然后再考虑从该进程的activitythread中获取安装的provider对象,然后在这个代理对象上进行增删改查的操作。

query方法如下:获得cursor指针主要查看ActivithThread中acquireProvider方法

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);
    if (unstableProvider == null) {
        return null;
    }
    IContentProvider stableProvider = null;
    Cursor qCursor = null;
    try {
        long startTime = SystemClock.uptimeMillis();
        //......
        try {
            qCursor = unstableProvider.query(mPackageName, uri, projection,
                    queryArgs, remoteCancellationSignal);
        } catch (DeadObjectException e) {
            //如果进程不存在的情况下
            unstableProviderDied(unstableProvider);
            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.
        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 {
       //......
    }
}

ApplicationContentResolver如下:

 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 acquireUnstableProvider(Context c, String auth) {
        return mMainThread.acquireProvider(c,
                ContentProvider.getAuthorityWithoutUserId(auth),
                resolveUserIdFromAuthority(auth), false);
    }
    //......
}

ActivityThread中acquireProvider如下:

public final IContentProvider acquireProvider(
        Context c, String auth, int userId, boolean stable) {
    //已存在,则直接返回        
    final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
    if (provider != null) {
        return provider;
    }
    ContentProviderHolder holder = null;
    try {
        //同步,保证先到先得
        synchronized (getGetProviderLock(auth, userId)) {
            holder = ActivityManager.getService().getContentProvider(
                    getApplicationThread(), auth, userId, stable);
        }
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
    if (holder == null) {
        Slog.e(TAG, "Failed to find provider info for " + auth);
        return null;
    }
    // 安装该provider
    holder = installProvider(c, holder, holder.info,
            true /*noisy*/, holder.noReleaseNeeded, stable);
    return holder.provider;
}

AMS中获取方法如下:

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

    synchronized(this) {
       //无法根据caller查找到对应app,则抛出security异常
        boolean checkCrossUser = true;
        checkTime(startTime, "getContentProviderImpl: getProviderByName");
        // 首先检查该content provider是否已发布
        cpr = mProviderMap.getProviderByName(name, userId);
        //......

        boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
        //该provider正在运行
        if (providerRunning) {
            cpi = cpr.info;
            String msg;
            checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
            //检查调用者是否拥有读取数据库权限,如没有,则抛出异常
            if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
                    != null) {
                throw new SecurityException(msg);
            }
            checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");

            if (r != null && cpr.canRunHere(r)) {
                //provider存在,并且进程存在,则直接返回
                ContentProviderHolder holder = cpr.newHolder(null);
                // don't give caller the provider object, it needs
                // to make its own.
                holder.provider = null;
                return holder;
            }
            // 正常app与instant ap之间不互相暴露
            try {
                if (AppGlobals.getPackageManager()
                        .resolveContentProvider(name, 0 /*flags*/, userId) == null) {
                    return null;
                }
            } catch (RemoteException e) {
            }

            final long origId = Binder.clearCallingIdentity();

            checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");

            //......

        if (!providerRunning) {
            try {
                checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
                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;
            }
            //检查singleton 属性,并且检查调用者权限
            //system ready前调用system provider 返回异常
            //system providers 未安装,抛出异常

            //明确provider归属用户,如果用户管理尚未启动,则不允许该provider运行
            if (!mUserController.isUserRunning(userId, 0)) {
                Slog.w(TAG, "Unable to launch app "
                        + cpi.applicationInfo.packageName + "/"
                        + cpi.applicationInfo.uid + " for provider "
                        + name + ": user " + userId + " is stopped");
                return null;
            }

            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);
                    cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
                } catch (RemoteException ex) {
                    // pm is in same process, this will never happen.
                } finally {
                    Binder.restoreCallingIdentity(ident);
                }
            }
            
            //......

            //如果provider尚未启动,则拉起它
            if (i >= N) {
                try {
                    // Content provider is now in use, its package can't be stopped.
                    // Use existing process if already started
                    if (proc != null && proc.thread != null && !proc.killed) {
                        if (!proc.pubProviders.containsKey(cpi.name)) {
                            try {
                                //进程存在后台,未被kill掉,调用该进程,安装provider
                                proc.thread.scheduleInstallProvider(cpi);
                            } catch (RemoteException e) {
                            }
                        }
                    } else {
                        //启动该provider所在进程,指定provider所在component
                        proc = startProcessLocked(cpi.processName,
                                cpr.appInfo, false, 0, "content provider",
                                new ComponentName(cpi.applicationInfo.packageName,
                                        cpi.name), false, false, false);
                                        
            }
        //......
    }

    //等待 provider 发布出来
    synchronized (cpr) {
        while (cpr.provider == null) {
            //......
            try {
                if (DEBUG_MU) Slog.v(TAG_MU,
                        "Waiting to start provider " + cpr
                        + " launchingApp=" + cpr.launchingApp);
                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;
}
private void installContentProviders(
        Context context, List<ProviderInfo> providers) {
    final ArrayList<ContentProviderHolder> results = new ArrayList<>();

    for (ProviderInfo cpi : providers) {
        if (DEBUG_PROVIDER) {
            StringBuilder buf = new StringBuilder(128);
            buf.append("Pub ");
            buf.append(cpi.authority);
            buf.append(": ");
            buf.append(cpi.name);
            Log.i(TAG, buf.toString());
        }
        //安装provider,通过将该provider加入到mProviderMap队列中
        ContentProviderHolder cph = installProvider(context, null, cpi,
                false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
        if (cph != null) {
            cph.noReleaseNeeded = true;
            results.add(cph);
        }
    }

    try {
        //将列表中的provider发布到AMS中的mProviderMap下的mSingletonByName队列中
        ActivityManager.getService().publishContentProviders(
            getApplicationThread(), results);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
}
private ContentProviderHolder installProvider(Context context,
        ContentProviderHolder holder, ProviderInfo info,
        boolean noisy, boolean noReleaseNeeded, boolean stable) {
    ContentProvider localProvider = null;
    IContentProvider provider;
    
    //参数检查,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) {
                provider = pr.mProvider;
            } else {
                holder = new ContentProviderHolder(info);
                holder.provider = provider;
                holder.noReleaseNeeded = true;
                //如果不存在,则将其加入到mProviderMap、 mLocalProviders、mLocalProvidersByName三个队列中
                pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                mLocalProviders.put(jBinder, pr);
                mLocalProvidersByName.put(cname, pr);
            }
            retHolder = pr.mHolder;
        } else {
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
            if (prc != null) {
                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 {
                //加入到mProviderMap队列中
                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队列中
                mProviderRefCountMap.put(jBinder, prc);
            }
            retHolder = prc.holder;
        }
    }
    return retHolder;
}
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
        ContentProvider localProvider, ContentProviderHolder holder) {
    final String auths[] = holder.info.authority.split(";");
    final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);

    if (provider != null) {
        // If this provider is hosted by the core OS and cannot be upgraded,
        // then I guess we're okay doing blocking calls to it.
        for (String auth : auths) {
            switch (auth) {
                case ContactsContract.AUTHORITY:
                case CallLog.AUTHORITY:
                case CallLog.SHADOW_AUTHORITY:
                case BlockedNumberContract.AUTHORITY:
                case CalendarContract.AUTHORITY:
                case Downloads.Impl.AUTHORITY:
                case "telephony":
                    Binder.allowBlocking(provider.asBinder());
            }
        }
    }

    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;
}
public final void publishContentProviders(IApplicationThread caller,
        List<ContentProviderHolder> providers) {
    if (providers == null) {
        return;
    }

    enforceNotIsolatedCaller("publishContentProviders");
    synchronized (this) {
        final ProcessRecord r = getRecordForAppLocked(caller);
        if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
        if (r == null) {
           //抛出异常
        }

        final long origId = Binder.clearCallingIdentity();

        final int N = providers.size();
        for (int i = 0; i < N; i++) {
            ContentProviderHolder src = providers.get(i);
            if (src == null || src.info == null || src.provider == null) {
                continue;
            }
            ContentProviderRecord dst = r.pubProviders.get(src.info.name);
            if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
            if (dst != null) {
                ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
                //加入到mProviderMap类的mSingletonByClass队列中
                mProviderMap.putProviderByClass(comp, dst);
                String names[] = dst.info.authority.split(";");
                for (int j = 0; j < names.length; j++) {
                    //加入mProviderMap类的mSingletonByName队列中
                    mProviderMap.putProviderByName(names[j], dst);
                }
                //处理等待启动provider队列,如果启动了,则会从队列中移出
                int launchingCount = mLaunchingProviders.size();
                int j;
                boolean wasInLaunchingProviders = false;
                for (j = 0; j < launchingCount; j++) {
                    if (mLaunchingProviders.get(j) == dst) {
                        mLaunchingProviders.remove(j);
                        wasInLaunchingProviders = true;
                        j--;
                        launchingCount--;
                    }
                }
                if (wasInLaunchingProviders) {
                    mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
                }
                synchronized (dst) {
                    dst.provider = src.provider;
                    dst.proc = r;
                    dst.notifyAll();
                }
                updateOomAdjLocked(r, true);
                maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                        src.info.authority);
            }
        }

        Binder.restoreCallingIdentity(origId);
    }
}

猜你喜欢

转载自blog.csdn.net/thh159/article/details/88379039