涉及文件:
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。
新建类继承自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 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 providers) {
final ArrayList 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 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);
}
}