Allow accessibility services to send Intent.ACSD

For targetSdk < S. For S, they can use the new
GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE action to dismiss the
notification shade.

Bug: 159334261
Test: Send Intent.ACSD from an a11y service and verify shade is
      collapsed when targetSdk < S, and exception thrown when targetSdk
      S+.
Change-Id: I0e4be3faef8efa53a0b8a08263e842e0c4b1553e
This commit is contained in:
Bernardo Rufino
2021-04-06 17:27:14 +01:00
parent 20953edc6f
commit 19a613c3da
4 changed files with 35 additions and 8 deletions

View File

@@ -18,6 +18,7 @@ package android.content;
import static android.content.ContentProvider.maybeAddUserId;
import android.accessibilityservice.AccessibilityService;
import android.annotation.AnyRes;
import android.annotation.BroadcastBehavior;
import android.annotation.IntDef;
@@ -2479,6 +2480,8 @@ public class Intent implements Parcelable, Cloneable {
* (eg. tests) is still able to use the intent. The platform will automatically collapse
* the proper system dialogs in the proper use-cases. For all others, the user is the one in
* control of closing dialogs.
*
* @see AccessibilityService#GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@RequiresPermission(android.Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS)

View File

@@ -1882,12 +1882,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mTempIntArray.add(resolveInfo.serviceInfo.applicationInfo.uid);
}
}
// Calling out with lock held, but to a lower-level service
// Calling out with lock held, but to lower-level services
final AudioManagerInternal audioManager =
LocalServices.getService(AudioManagerInternal.class);
if (audioManager != null) {
audioManager.setAccessibilityServiceUids(mTempIntArray);
}
mActivityTaskManagerService.setAccessibilityServiceUids(mTempIntArray);
updateAccessibilityEnabledSettingLocked(userState);
}

View File

@@ -32,6 +32,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.service.voice.IVoiceInteractionSession;
import android.util.IntArray;
import android.util.proto.ProtoOutputStream;
import android.window.TaskSnapshot;
@@ -221,6 +222,11 @@ public abstract class ActivityTaskManagerInternal {
public abstract void setBackgroundActivityStartCallback(
@Nullable BackgroundActivityStartCallback callback);
/**
* Sets the list of UIDs that contain an active accessibility service.
*/
public abstract void setAccessibilityServiceUids(IntArray uids);
/**
* Start activity {@code intent} without calling user-id check.
*

View File

@@ -214,6 +214,7 @@ import android.telecom.TelecomManager;
import android.text.format.TimeMigrationUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -677,6 +678,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Nullable
private BackgroundActivityStartCallback mBackgroundActivityStartCallback;
private int[] mAccessibilityServiceUids = new int[0];
private int mDeviceOwnerUid = Process.INVALID_UID;
private final class SettingObserver extends ContentObserver {
@@ -2990,20 +2993,26 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return true;
}
}
// This covers the case where the app is displaying some UI on top of the notification shade
// and wants to start an activity. The app then sends the intent in order to move the
// notification shade out of the way and show the activity to the user. This is fine since
// the caller already has privilege to show a visible window on top of the notification
// shade, so it can already prevent the user from accessing the shade if it wants to.
// We only allow for targetSdk < S, for S+ we automatically collapse the shade on
// startActivity() for these apps.
if (!CompatChanges.isChangeEnabled(LOCK_DOWN_CLOSE_SYSTEM_DIALOGS, uid)) {
synchronized (mGlobalLock) {
// This covers the case where the app is displaying some UI on top of the
// notification shade and wants to start an activity. The app then sends the intent
// in order to move the notification shade out of the way and show the activity to
// the user. This is fine since the caller already has privilege to show a visible
// window on top of the notification shade, so it can already prevent the user from
// accessing the shade if it wants to. We only allow for targetSdk < S, for S+ we
// automatically collapse the shade on startActivity() for these apps.
// It's ok that the owner of the shade is not allowed *per this rule* because it has
// BROADCAST_CLOSE_SYSTEM_DIALOGS (SystemUI), so it would fall into that rule.
if (mRootWindowContainer.hasVisibleWindowAboveButDoesNotOwnNotificationShade(uid)) {
return true;
}
// Accessibility services are allowed to send the intent unless they are targeting
// S+, in which case they should use {@link AccessibilityService
// #GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE} to dismiss the notification shade.
if (ArrayUtils.contains(mAccessibilityServiceUids, uid)) {
return true;
}
}
}
return false;
@@ -5122,11 +5131,19 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return mVisibleActivityProcessTracker.hasResumedActivity(uid);
}
@Override
public void setBackgroundActivityStartCallback(
@Nullable BackgroundActivityStartCallback backgroundActivityStartCallback) {
mBackgroundActivityStartCallback = backgroundActivityStartCallback;
}
@Override
public void setAccessibilityServiceUids(IntArray uids) {
synchronized (mGlobalLock) {
mAccessibilityServiceUids = uids.toArray();
}
}
@Override
public int startActivitiesAsPackage(String packageName, @Nullable String featureId,
int userId, Intent[] intents, Bundle bOptions) {