欢迎转载,转载请注明出处 xianzhu21.space

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(),最后也是会调用到 ActivityManagerService 的 checkPermission()

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 的时候检查是否声明了权限。

// frameworks/base/core/java/android/os/PowerManager.java
/**
    * 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();
    }
}

Xianzhu21

Xianzhu21
An Android framework developer.

Window Touchable Region

当用户触屏后,InputReader 从驱动读取一个输入事件加入到队列,InputDispatcher 从队列中读取一个输入事件准备分发。如果该输入事件是一个触摸事件...
Continue reading

Dropping event bug in Dialog

Published on March 10, 2020

InputChannel and InputDispatcher in Android

Published on February 27, 2020