SystemService 是在 system_server 进程中执行,因此权限也比较高。虽然可以在 API 中做一些访问控制,但是因为有反射、动态代理等技术的存在,在 SystemService 的实际方法实现中做访问控制是必要的。

ActivityManagerService 中定义了几个 enforce 开头的方法,这些都是访问控制相关的。

enforceCallingPermission() 是检查调用者是否拥有指定的 permission,最终调用的是 PackageManagerService 类的 checkUidPermission()

// com.android.server.am.ActivityManagerService
/**
 * This can be called with or without the global lock held.
 */
void enforceCallingPermission(String permission, String func) {
    if (checkCallingPermission(permission)
            == PackageManager.PERMISSION_GRANTED) {
        return;
    }
    throw new SecurityException(msg);
}

/**
 * Binder IPC calls go through the public entry point.
 * This can be called with or without the global lock held.
 */
int checkCallingPermission(String permission) {
    return checkPermission(permission, Binder.getCallingPid(),
            UserHandle.getAppId(Binder.getCallingUid()));
}

public int checkPermission(String permission, int pid, int uid) {
    if (permission == null) {
        return PackageManager.PERMISSION_DENIED;
    }
    return checkComponentPermission(permission, pid, uid, -1, true);
}

int checkComponentPermission(String permission, int pid, int uid,
        int owningUid, boolean exported) {
    if (pid == MY_PID) {
        return PackageManager.PERMISSION_GRANTED;
    }
    return ActivityManager.checkComponentPermission(permission, uid,
            owningUid, exported);
}

// android.app.ActivityManager
public static int checkComponentPermission(String permission, int uid,
        int owningUid, boolean exported) {
    // Root, system server get to do everything.
    final int appId = UserHandle.getAppId(uid);
    if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
        return PackageManager.PERMISSION_GRANTED;
    }
    // If there is a uid that owns whatever is being accessed, it has
    // blanket access to it regardless of the permissions it requires.
    if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
        return PackageManager.PERMISSION_GRANTED;
    }
    if (permission == null) {
        return PackageManager.PERMISSION_GRANTED;
    }
    try {
        return AppGlobals.getPackageManager()
                .checkUidPermission(permission, uid);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
}}

AppOpsService 中定义了方法 enforceManageAppOpsModes()。它会调用 Context 类的 enforcePermission(),最后也是会调用到 ActivityManagerServicecheckPermission()

Context 类中已经定义了几个供使用的访问控制相关的方法:

int checkPermission(String permission, int pid, int uid)
int checkPermission(String permission, int pid, int uid, IBinder callerToken);
int checkCallingPermission(String permission);
int checkCallingOrSelfPermission(String permission);
int checkSelfPermission(String permission);

void enforcePermission(String permission, int pid, int uid, String message);
void enforceCallingPermission(String permission, String message);
void enforceCallingOrSelfPermission(String permission, String message);

这么一看,SystemService 中的访问控制实际还是调用的 PackageManagerService 类的 checkUidPermission(),即 Android permission 机制。

在 API 的方法中可以使用 @RequiresPermission 注解,这样可以在构建 App 的时候检查是否声明了权限。

/**
 * Notifies the power manager that user activity happened.
 * <p>
 * Resets the auto-off timer and brightens the screen if the device
 * is not asleep.  This is what happens normally when a key or the touch
 * screen is pressed or when some other user activity occurs.
 * This method does not wake up the device if it has been put to sleep.
 * </p><p>
 * Requires the {@link android.Manifest.permission#DEVICE_POWER} or
 * {@link android.Manifest.permission#USER_ACTIVITY} permission.
 * </p>
 *
 * @param when The time of the user activity, in the {@link SystemClock#uptimeMillis()}
 * time base.  This timestamp is used to correctly order the user activity request with
 * other power management functions.  It should be set
 * to the timestamp of the input event that caused the user activity.
 * @param event The user activity event.
 * @param flags Optional user activity flags.
 *
 * @see #wakeUp
 * @see #goToSleep
 *
 * @hide Requires signature or system permission.
 */
@SystemApi
@RequiresPermission(anyOf = {
        android.Manifest.permission.DEVICE_POWER,
        android.Manifest.permission.USER_ACTIVITY
})
public void userActivity(long when, int event, int flags) {
    try {
        mService.userActivity(when, event, flags);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}