烦恼一般都是想太多了。

0%

Android的权限检查过程

是从追踪 InputManagerServer 的注入输入事件开始的过程。我们在之前的 中看到,这个类并没有检查权限,但是为什么会提示权限不够违例呢。事实上就是其在 native 层进行检查

其基本过程是通过 InputManager 从 ServiceManager 处拿到 InputManagerService 的 Binder ,然后 Binder 调用 InputManagerService 的 injectInputEvent 方法 进行注入。

InputManagerService.injectInputEvent

在这里,就会获得调用进程的 uid(用户ID),pid(进程ID),之后通过 C 层服务进行注入,在这里,并没有进行任何权限相关的判断。

@Override // Binder call
public boolean injectInputEvent(InputEvent event, int mode) {
return injectInputEventInternal(event, mode);
}

private boolean injectInputEventInternal(InputEvent event, int mode) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
&& mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
&& mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
throw new IllegalArgumentException("mode is invalid");
}

final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
final int result;
try {
result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
} finally {
Binder.restoreCallingIdentity(ident);
}
switch (result) {
case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
throw new SecurityException(
"Injecting to another application requires INJECT_EVENTS permission");
case INPUT_EVENT_INJECTION_SUCCEEDED:
return true;
case INPUT_EVENT_INJECTION_TIMED_OUT:
Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
return false;
case INPUT_EVENT_INJECTION_FAILED:
default:
Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
return false;
}
}

InputManagerService.nativeInjectInputEvent

代码逻辑就通过 JNI 转到了 C 层。这个方法会根据注入事件的类型(android/view/KeyEvent 键盘事件,android/view/MotionEvent 触摸事件来进行不同的逻辑分发)。

最终,是获得 C 层的 InputDispatcher 进行注入。


static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputEventObj, jint injectorPid, jint injectorUid,
jint syncMode, jint timeoutMillis, jint policyFlags) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
KeyEvent keyEvent;
status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
if (status) {
jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
return INPUT_EVENT_INJECTION_FAILED;
}

return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
& keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis,
uint32_t(policyFlags));
} else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);
if (!motionEvent) {
jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");
return INPUT_EVENT_INJECTION_FAILED;
}

return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis,
uint32_t(policyFlags));
} else {
jniThrowRuntimeException(env, "Invalid input event type.");
return INPUT_EVENT_INJECTION_FAILED;
}
}

InputDispatcher::injectInputEvent

这段代码比较长,总结起来就是做了以下几件事情:

  1. 根据 uid, pid 检查是否有权限。
  2. 根据是 key 还是 motion 事件类型来构造 KeyEntry, MotionEntry。然后将事件加入队列。
  3. 唤醒 InputDispatcherThread 线程,分发事件。
  4. 获取注入的结果。返回。
int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid,
int32_t injectorUid, int32_t syncMode,
int32_t timeoutMillis, uint32_t policyFlags) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
"syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x",
event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags);
#endif

nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);

policyFlags |= POLICY_FLAG_INJECTED;
if (hasInjectionPermission(injectorPid, injectorUid)) {
policyFlags |= POLICY_FLAG_TRUSTED;
}

EventEntry* firstInjectedEntry;
EventEntry* lastInjectedEntry;
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
KeyEvent keyEvent;
keyEvent.initialize(*static_cast<const KeyEvent*>(event));
int32_t action = keyEvent.getAction();
if (!validateKeyEvent(action)) {
return INPUT_EVENT_INJECTION_FAILED;
}

int32_t flags = keyEvent.getFlags();
int32_t keyCode = keyEvent.getKeyCode();
int32_t metaState = keyEvent.getMetaState();
accelerateMetaShortcuts(keyEvent.getDeviceId(), action,
/*byref*/ keyCode, /*byref*/ metaState);
keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(),
keyEvent.getDisplayId(), action, flags, keyCode,
keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(),
keyEvent.getDownTime(), keyEvent.getEventTime());

if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
policyFlags |= POLICY_FLAG_VIRTUAL;
}

if (!(policyFlags & POLICY_FLAG_FILTERED)) {
android::base::Timer t;
mPolicy->interceptKeyBeforeQueueing(&keyEvent, /*byref*/ policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
std::to_string(t.duration().count()).c_str());
}
}

mLock.lock();
firstInjectedEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM,
keyEvent.getEventTime(), keyEvent.getDeviceId(),
keyEvent.getSource(), keyEvent.getDisplayId(),
policyFlags, action, flags, keyEvent.getKeyCode(),
keyEvent.getScanCode(), keyEvent.getMetaState(),
keyEvent.getRepeatCount(), keyEvent.getDownTime());
lastInjectedEntry = firstInjectedEntry;
break;
}

case AINPUT_EVENT_TYPE_MOTION: {
const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
int32_t action = motionEvent->getAction();
size_t pointerCount = motionEvent->getPointerCount();
const PointerProperties* pointerProperties = motionEvent->getPointerProperties();
int32_t actionButton = motionEvent->getActionButton();
int32_t displayId = motionEvent->getDisplayId();
if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) {
return INPUT_EVENT_INJECTION_FAILED;
}

if (!(policyFlags & POLICY_FLAG_FILTERED)) {
nsecs_t eventTime = motionEvent->getEventTime();
android::base::Timer t;
mPolicy->interceptMotionBeforeQueueing(displayId, eventTime, /*byref*/ policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
std::to_string(t.duration().count()).c_str());
}
}

mLock.lock();
const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
firstInjectedEntry =
new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(),
motionEvent->getDisplayId(), policyFlags, action, actionButton,
motionEvent->getFlags(), motionEvent->getMetaState(),
motionEvent->getButtonState(), motionEvent->getClassification(),
motionEvent->getEdgeFlags(), motionEvent->getXPrecision(),
motionEvent->getYPrecision(), motionEvent->getDownTime(),
uint32_t(pointerCount), pointerProperties, samplePointerCoords,
motionEvent->getXOffset(), motionEvent->getYOffset());
lastInjectedEntry = firstInjectedEntry;
for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
sampleEventTimes += 1;
samplePointerCoords += pointerCount;
MotionEntry* nextInjectedEntry =
new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(),
motionEvent->getDisplayId(), policyFlags, action,
actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
motionEvent->getClassification(),
motionEvent->getEdgeFlags(), motionEvent->getXPrecision(),
motionEvent->getYPrecision(), motionEvent->getDownTime(),
uint32_t(pointerCount), pointerProperties,
samplePointerCoords, motionEvent->getXOffset(),
motionEvent->getYOffset());
lastInjectedEntry->next = nextInjectedEntry;
lastInjectedEntry = nextInjectedEntry;
}
break;
}

default:
ALOGW("Cannot inject event of type %d", event->getType());
return INPUT_EVENT_INJECTION_FAILED;
}

InjectionState* injectionState = new InjectionState(injectorPid, injectorUid);
if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
injectionState->injectionIsAsync = true;
}

injectionState->refCount += 1;
lastInjectedEntry->injectionState = injectionState;

bool needWake = false;
for (EventEntry* entry = firstInjectedEntry; entry != nullptr;) {
EventEntry* nextEntry = entry->next;
needWake |= enqueueInboundEventLocked(entry);
entry = nextEntry;
}

mLock.unlock();

if (needWake) {
mLooper->wake();
}

int32_t injectionResult;
{ // acquire lock
std::unique_lock _l(mLock);

if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
} else {
for (;;) {
injectionResult = injectionState->injectionResult;
if (injectionResult != INPUT_EVENT_INJECTION_PENDING) {
break;
}

nsecs_t remainingTimeout = endTime - now();
if (remainingTimeout <= 0) {
#if DEBUG_INJECTION
ALOGD("injectInputEvent - Timed out waiting for injection result "
"to become available.");
#endif
injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
break;
}

mInjectionResultAvailable.wait_for(_l, std::chrono::nanoseconds(remainingTimeout));
}

if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED &&
syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) {
while (injectionState->pendingForegroundDispatches != 0) {
#if DEBUG_INJECTION
ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.",
injectionState->pendingForegroundDispatches);
#endif
nsecs_t remainingTimeout = endTime - now();
if (remainingTimeout <= 0) {
#if DEBUG_INJECTION
ALOGD("injectInputEvent - Timed out waiting for pending foreground "
"dispatches to finish.");
#endif
injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
break;
}

mInjectionSyncFinished.wait_for(_l, std::chrono::nanoseconds(remainingTimeout));
}
}
}

injectionState->release();
} // release lock

#if DEBUG_INJECTION
ALOGD("injectInputEvent - Finished with result %d. "
"injectorPid=%d, injectorUid=%d",
injectionResult, injectorPid, injectorUid);
#endif

return injectionResult;
}

InputDispatcher::hasInjectionPermission

权限检测。

  1. 如果 uid = 0 ,超级用户,有权限。
  2. 调用 NativeInputManager 来进行检查。
bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
return injectorUid == 0 ||
mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
}

NativeInputManager::checkInjectEventsPermissionNonReentrant

在这里,其实又是将检测的逻辑,丢给了 InputManagerService。看来在 C 层,只会检查是否是超级用户,而其他的权限检测,则交给了安卓的权限框架了。

bool NativeInputManager::checkInjectEventsPermissionNonReentrant(
int32_t injectorPid, int32_t injectorUid) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
jboolean result = env->CallBooleanMethod(mServiceObj,
gServiceClassInfo.checkInjectEventsPermission, injectorPid, injectorUid);
if (checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission")) {
result = false;
}
return result;
}

InputManagerService.checkInjectEventsPermission

这是通过一个 Context 上下文的方法来进行检查的。

// Native callback.
private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
}

Context[Impl].checkPermission

这个将权限的检查交给 ActivityManagerService。但如果没有存在 ActivityManagerService 服务的时候,只有超级用户进程,和系统用户进程,权限检查才能通过。

在这里,ActivityManagerService 的通信,是通过 Binder 进行的。

@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}

final IActivityManager am = ActivityManager.getService();
if (am == null) {
// Well this is super awkward; we somehow don't have an active
// ActivityManager instance. If we're testing a root or system
// UID, then they totally have whatever permission this is.
final int appId = UserHandle.getAppId(uid);
if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission);
return PackageManager.PERMISSION_GRANTED;
}
Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold "
+ permission);
return PackageManager.PERMISSION_DENIED;
}

try {
return am.checkPermission(permission, pid, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

ActivityManagerService.checkPermission

比较奇怪,ActivityManagerService 的检查,只会检查是不是与 ActivityManagerService 所属进程的ID相同,然后就将检查交给了 ActivityManager。

/**
* As the only public entry point for permissions checking, this method
* can enforce the semantic that requesting a check on a null global
* permission is automatically denied. (Internally a null permission
* string is used when calling {@link #checkComponentPermission} in cases
* when only uid-based security is needed.)
*
* This can be called with or without the global lock held.
*/
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
return PackageManager.PERMISSION_DENIED;
}
return checkComponentPermission(permission, pid, uid, -1, true);
}


public static 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);
}

ActivityManager.checkComponentPermission

这个方法,SDK 是无法调用的,我们自己写的 APP 是无法调用这个API的。

同样会进行检查:

  1. 根据 uid 获取 appId,root, system_server 进程默认有权限。
  2. 隔离的进程什么权限都不会获得。
  3. 如果同一个 APP,有两个 uid,其中一个已经获取了这个权限,那么这个检查也会通过。
  4. 通过 PackageManager 来检查 uid。
/** @hide */
@UnsupportedAppUsage
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;
}
// Isolated processes don't get any permissions.
if (UserHandle.isIsolated(uid)) {
return PackageManager.PERMISSION_DENIED;
}
// 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 the target is not exported, then nobody else can get to it.
if (!exported) {
/*
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
here);
*/
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
return PackageManager.PERMISSION_GRANTED;
}
try {
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

PackageManagerService.checkUidPermission

这个有分两种情况了,一个是直接让 PermissionManagerService 去检查,还有就是通过 CheckPermissionDelegate 去检查。什么时候有 CheckPermissionDelegate 还没有研究,继续往下看通过 PermissionManager 检查。

CheckPermissionDelegate 是自定义的一个权限检查代理,就只有两个方法:

/** Interface to override permission checks via composition */
public interface CheckPermissionDelegate {
/**
* Allows overriding check permission behavior.
*
* @param permName The permission to check.
* @param pkgName The package for which to check.
* @param userId The user for which to check.
* @param superImpl The super implementation.
* @return The check permission result.
*/
int checkPermission(String permName, String pkgName, int userId,
TriFunction<String, String, Integer, Integer> superImpl);

/**
* Allows overriding check UID permission behavior.
*
* @param permName The permission to check.
* @param uid The UID for which to check.
* @param superImpl The super implementation.
* @return The check permission result.
*/
int checkUidPermission(String permName, int uid,
BiFunction<String, Integer, Integer> superImpl);
}
@Override
public int checkUidPermission(String permName, int uid) {
final CheckPermissionDelegate checkPermissionDelegate;
synchronized (mPackages) {
if (mCheckPermissionDelegate == null) {
return checkUidPermissionImpl(permName, uid);
}
checkPermissionDelegate = mCheckPermissionDelegate;
}
return checkPermissionDelegate.checkUidPermission(permName, uid,
PackageManagerService.this::checkUidPermissionImpl);
}

private int checkUidPermissionImpl(String permName, int uid) {
synchronized (mPackages) {
final String[] packageNames = getPackagesForUid(uid);
PackageParser.Package pkg = null;
final int N = packageNames == null ? 0 : packageNames.length;
for (int i = 0; pkg == null && i < N; i++) {
pkg = mPackages.get(packageNames[i]);
}
return mPermissionManager.checkUidPermission(permName, pkg, uid, getCallingUid());
}
}

PermissionManagerService.checkUidPermission

这个服务来负责管理所有的权限相关的任务。在这里就会检查 APP的 权限表,查看是不是已经给了对应的权限了。

private int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
int callingUid) {
final int callingUserId = UserHandle.getUserId(callingUid);
final boolean isCallerInstantApp =
mPackageManagerInt.getInstantAppPackageName(callingUid) != null;
final boolean isUidInstantApp =
mPackageManagerInt.getInstantAppPackageName(uid) != null;
final int userId = UserHandle.getUserId(uid);
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
}

if (pkg != null) {
if (pkg.mSharedUserId != null) {
if (isCallerInstantApp) {
return PackageManager.PERMISSION_DENIED;
}
} else if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) {
return PackageManager.PERMISSION_DENIED;
}
final PermissionsState permissionsState =
((PackageSetting) pkg.mExtras).getPermissionsState();
if (permissionsState.hasPermission(permName, userId)) {
if (isUidInstantApp) {
if (mSettings.isPermissionInstant(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
} else {
return PackageManager.PERMISSION_GRANTED;
}
}
if (isImpliedPermissionGranted(permissionsState, permName, userId)) {
return PackageManager.PERMISSION_GRANTED;
}
} else {
ArraySet<String> perms = mSystemPermissions.get(uid);
if (perms != null) {
if (perms.contains(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
if (FULLER_PERMISSION_MAP.containsKey(permName)
&& perms.contains(FULLER_PERMISSION_MAP.get(permName))) {
return PackageManager.PERMISSION_GRANTED;
}
}
}
return PackageManager.PERMISSION_DENIED;
}

private int checkPermission(String permName, String pkgName, int callingUid, int userId) {
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
}

final PackageParser.Package pkg = mPackageManagerInt.getPackage(pkgName);
if (pkg != null && pkg.mExtras != null) {
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
return PackageManager.PERMISSION_DENIED;
}
final PackageSetting ps = (PackageSetting) pkg.mExtras;
final boolean instantApp = ps.getInstantApp(userId);
final PermissionsState permissionsState = ps.getPermissionsState();
if (permissionsState.hasPermission(permName, userId)) {
if (instantApp) {
synchronized (mLock) {
BasePermission bp = mSettings.getPermissionLocked(permName);
if (bp != null && bp.isInstant()) {
return PackageManager.PERMISSION_GRANTED;
}
}
} else {
return PackageManager.PERMISSION_GRANTED;
}
}
if (isImpliedPermissionGranted(permissionsState, permName, userId)) {
return PackageManager.PERMISSION_GRANTED;
}
}

return PackageManager.PERMISSION_DENIED;
}

总结

实际上,如果不是 root 或者 system_server 进程的时候,其权限都是由 PermissionManagerService 进行检查的。

在 C 层和 PermissionManagerService 之外,都只会检查进程 ID,UID 而不会检查权限表。