Android ContentProvider、ContentResolver/ContentObserver 修改监听流程
以 Settings.System.putInt(mContentResolver, Settings.System.SCREEN_BRIGHTNESS, mCurrentValue); 为例。putInt 最后也是使用 ContentProvider 保存。
Settings 中 putInt 后最终执行 putStringForUser函数
public boolean putStringForUser(ContentResolver cr, String name, String value,
String tag, boolean makeDefault, final int userHandle) {
try {
Bundle arg = new Bundle();
arg.putString(Settings.NameValueTable.VALUE, value);
arg.putInt(CALL_METHOD_USER_KEY, userHandle);
if (tag != null) {
arg.putString(CALL_METHOD_TAG_KEY, tag);
}
if (makeDefault) {
arg.putBoolean(CALL_METHOD_MAKE_DEFAULT_KEY, true);
}
IContentProvider cp = mProviderHolder.getProvider(cr);
cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
mCallSetCommand, name, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
return false;
}
return true;
}
所设置的 value 保存在 bundle 中调用 call 传递。
IContentProvider 是一个接口类,ContentProviderNative 是其抽象实现类。call 函数最后由 ContentProvider 内部类 Transport (继承 ContentProviderNative)中实现处理。如下
@Override
public Bundle call(String callingPkg, String authority, String method, @Nullable String arg,
@Nullable Bundle extras) {
validateIncomingAuthority(authority);
Bundle.setDefusable(extras, true);
Trace.traceBegin(TRACE_TAG_DATABASE, "call");
final String original = setCallingPackage(callingPkg);
try {
return mInterface.call(authority, method, arg, extras);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
} finally {
setCallingPackage(original);
Trace.traceEnd(TRACE_TAG_DATABASE);
}
}
mInterface 是 ContentInterface 实例,ContentProvider 是 ContentInterface 实现类
mInterface.call(authority, method, arg, extras);
这行实际走的是 ContentProvider 中的 call 函数。
@Override
public @Nullable Bundle call(@NonNull String authority, @NonNull String method,
@Nullable String arg, @Nullable Bundle extras) {
return call(method, arg, extras);
}
public @Nullable Bundle call(@NonNull String method, @Nullable String arg,
@Nullable Bundle extras) {
return null;
}
可以看到结果走到最后是
return null;
再找到它的子类,这里使用的是 SettingsProvider.java ,所以 call 函数接下来操作在这里实现。
@Override
public Bundle call(String method, String name, Bundle args) {
final int requestingUserId = getRequestingUserId(args);
switch (method) {
... ...
case Settings.CALL_METHOD_PUT_SYSTEM: {
String value = getSettingValue(args);
insertSystemSetting(name, value, requestingUserId);
break;
}
... ...
default: {
Slog.w(LOG_TAG, "call() with invalid method: " + method);
} break;
}
return null;
}
根据 method 类型继续处理。走到 mutateSystemSetting 中。
private boolean mutateSystemSetting(String name, String value, int runAsUserId,
int operation) {
if (!hasWriteSecureSettingsPermission()) {
// If the caller doesn't hold WRITE_SECURE_SETTINGS, we verify whether this
// operation is allowed for the calling package through appops.
if (!Settings.checkAndNoteWriteSettingsOperation(getContext(),
Binder.getCallingUid(), getCallingPackage(), true)) {
return false;
}
}
// Resolve the userId on whose behalf the call is made.
final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId);
if (name != null && mUserManagerInternal.isSettingRestrictedForUser(
name, callingUserId, value, Binder.getCallingUid())) {
return false;
}
// Enforce what the calling package can mutate the system settings.
enforceRestrictedSystemSettingsMutationForCallingPackage(operation, name, callingUserId);
// Mutate the value.
synchronized (mLock) {
switch (operation) {
case MUTATION_OPERATION_INSERT: {
validateSystemSettingValue(name, value);
return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SYSTEM,
owningUserId, name, value, null, false, getCallingPackage(),
false, null);
}
case MUTATION_OPERATION_DELETE: {
return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_SYSTEM,
owningUserId, name, false, null);
}
case MUTATION_OPERATION_UPDATE: {
validateSystemSettingValue(name, value);
return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_SYSTEM,
owningUserId, name, value, null, false, getCallingPackage(),
false, null);
}
}
return false;
}
}
在这里处理下权限的,和根据设置值的类型处理。我们是 update 的,走 MUTATION_OPERATION_UPDATE 调用 updateSettingLocked
public boolean updateSettingLocked(int type, int userId, String name, String value,
String tag, boolean makeDefault, String packageName, boolean forceNotify,
Set<String> criticalSettings) {
final int key = makeKey(type, userId);
boolean success = false;
SettingsState settingsState = peekSettingsStateLocked(key);
if (settingsState != null) {
success = settingsState.updateSettingLocked(name, value, tag,
makeDefault, packageName);
}
if (success && criticalSettings != null && criticalSettings.contains(name)) {
settingsState.persistSyncLocked();
}
if (forceNotify || success) {
notifyForSettingsChange(key, name);
}
return success;
}
在 updateSettingLocked 成功后,使用 notifyForSettingsChange 通知 key 更新成功。走到 notifySettingChangeForRunningUsers 中
private void notifySettingChangeForRunningUsers(int key, String name) {
// Important: No need to update generation for each user as there
// is a singleton generation entry for the global settings which
// is already incremented be the caller.
final Uri uri = getNotificationUriFor(key, name);
final List<UserInfo> users = mUserManager.getUsers(/*excludeDying*/ true);
for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id;
if (mUserManager.isUserRunning(UserHandle.of(userId))) {
mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
userId, 0, uri).sendToTarget();
}
}
}
... ...
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_NOTIFY_URI_CHANGED: {
final int userId = msg.arg1;
Uri uri = (Uri) msg.obj;
try {
getContext().getContentResolver().notifyChange(uri, null, true, userId);
} catch (SecurityException e) {
Slog.w(LOG_TAG, "Failed to notify for " + userId + ": " + uri, e);
}
if (DEBUG || true) {
Slog.v(LOG_TAG, "Notifying for " + userId + ": " + uri);
}
} break;
case MSG_NOTIFY_DATA_CHANGED: {
mBackupManager.dataChanged();
} break;
}
}
}
通过发送 MSG_NOTIFY_URI_CHANGED 最后调用
getContext().getContentResolver().notifyChange(uri, null, true, userId);
ContentResolver 就是接受类,内部再通过 ContentService 去调度通知。
/**
* Notify registered observers within the designated user(s) that a row was updated.
*
* @hide
*/
public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
@UserIdInt int userHandle) {
try {
getContentService().notifyChange(
uri, observer == null ? null : observer.getContentObserver(),
observer != null && observer.deliverSelfNotifications(), flags,
userHandle, mTargetSdkVersion, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
# ContentService.java
@Override
public void notifyChange(Uri uri, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags, int userHandle,
int targetSdkVersion, String callingPackage) {
... ...
try {
ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
synchronized (mRootNode) {
mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
flags, userHandle, calls);
}
final int numCalls = calls.size();
for (int i=0; i<numCalls; i++) {
ObserverCall oc = calls.get(i);
try {
oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
if (DEBUG) Slog.d(TAG, "Notified " + oc.mObserver + " of " + "update at "
+ uri);
} catch (RemoteException ex) {
}
}
... ...
}
最后在系统 ContentService 中,一个for循环通知所有注册的 ContentObserver 。在 ContentObserver 中监听属性值变化。
mSettingsObserver = new SettingsObserver(mHandler);
// 注册Observer
mContext.getContentResolver().registerContentObserver(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), false, mSettingsObserver, UserHandle.USER_ALL);
private final class SettingsObserver extends ContentObserver {
public SettingsObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
synchronized (mLock) {
}
}
}