From c511e019f0ed5adff773b0787f6848101a32b8a0 Mon Sep 17 00:00:00 2001 From: Fabian Kozynski Date: Tue, 14 Sep 2021 12:18:59 -0400 Subject: [PATCH 1/2] Make API one-way Convert the return values to values that will be returned through the callback. Separate the ranges by SUCCESS of the request or ERROR. Test: CTS tests Fixes: 199829900 Change-Id: If32083e52ed87a79953c952bbaadd8d977e0226c --- core/api/current.txt | 13 ++-- core/java/android/app/StatusBarManager.java | 63 +++++++++---------- .../internal/statusbar/IStatusBarService.aidl | 2 +- .../external/TileServiceRequestController.kt | 2 +- .../statusbar/StatusBarManagerService.java | 24 +++++-- 5 files changed, 57 insertions(+), 47 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index a1f6352776460..46afb9d0bbe35 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -6698,13 +6698,12 @@ package android.app { } public class StatusBarManager { - method public int requestAddTileService(@NonNull android.content.ComponentName, @NonNull CharSequence, @NonNull android.graphics.drawable.Icon, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); - field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT = 3; // 0x3 - field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE = 1; // 0x1 - field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER = 4; // 0x4 - field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_REQUEST_IN_PROGRESS = 2; // 0x2 - field public static final int TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON = 5; // 0x5 - field public static final int TILE_ADD_REQUEST_ANSWER_SUCCESS = 0; // 0x0 + method public void requestAddTileService(@NonNull android.content.ComponentName, @NonNull CharSequence, @NonNull android.graphics.drawable.Icon, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); + field public static final int TILE_ADD_REQUEST_ERROR_BAD_COMPONENT = 1002; // 0x3ea + field public static final int TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE = 1000; // 0x3e8 + field public static final int TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER = 1003; // 0x3eb + field public static final int TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE = 1004; // 0x3ec + field public static final int TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS = 1001; // 0x3e9 field public static final int TILE_ADD_REQUEST_RESULT_TILE_ADDED = 2; // 0x2 field public static final int TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED = 1; // 0x1 field public static final int TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED = 0; // 0x0 diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index ee50634492bba..53dcef75da005 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -228,55 +228,53 @@ public class StatusBarManager { /** @hide */ public static final int TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED = 3; - /** @hide */ - @IntDef(prefix = {"TILE_ADD_REQUEST_RESULT_"}, value = { - TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED, - TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED, - TILE_ADD_REQUEST_RESULT_TILE_ADDED, - TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED - }) - @Retention(RetentionPolicy.SOURCE) - public @interface RequestResult {} - /** - * Indicates that the request was sent successfully. Does not indicate that the user - * has accepted the request. + * Values greater or equal to this value indicate an error in the request. */ - public static final int TILE_ADD_REQUEST_ANSWER_SUCCESS = 0; + private static final int TILE_ADD_REQUEST_FIRST_ERROR_CODE = 1000; + /** * Indicates that this package does not match that of the * {@link android.service.quicksettings.TileService}. */ - public static final int TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE = 1; + public static final int TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE = + TILE_ADD_REQUEST_FIRST_ERROR_CODE; /** * Indicates that there's a request in progress for this package. */ - public static final int TILE_ADD_REQUEST_ANSWER_FAILED_REQUEST_IN_PROGRESS = 2; + public static final int TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS = + TILE_ADD_REQUEST_FIRST_ERROR_CODE + 1; /** * Indicates that the component does not match an enabled * {@link android.service.quicksettings.TileService} for the current user. */ - public static final int TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT = 3; + public static final int TILE_ADD_REQUEST_ERROR_BAD_COMPONENT = + TILE_ADD_REQUEST_FIRST_ERROR_CODE + 2; /** * Indicates that the user is not the current user. */ - public static final int TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER = 4; + public static final int TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER = + TILE_ADD_REQUEST_FIRST_ERROR_CODE + 3; /** - * The request could not be processed due to an unkonwn reason. + * The request could not be processed because no fulfilling service was found. This could be + * a temporary issue (for example, SystemUI has crashed). */ - public static final int TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON = 5; + public static final int TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE = + TILE_ADD_REQUEST_FIRST_ERROR_CODE + 4; /** @hide */ - @IntDef(prefix = {"TILE_ADD_REQUEST_ANSWER_"}, value = { - TILE_ADD_REQUEST_ANSWER_SUCCESS, - TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE, - TILE_ADD_REQUEST_ANSWER_FAILED_REQUEST_IN_PROGRESS, - TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT, - TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER, - TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON + @IntDef(prefix = {"TILE_ADD_REQUEST"}, value = { + TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED, + TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED, + TILE_ADD_REQUEST_RESULT_TILE_ADDED, + TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE, + TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS, + TILE_ADD_REQUEST_ERROR_BAD_COMPONENT, + TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER, + TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE }) @Retention(RetentionPolicy.SOURCE) - public @interface RequestAnswer {} + public @interface RequestResult {} @UnsupportedAppUsage private Context mContext; @@ -626,12 +624,10 @@ public class StatusBarManager { * @param icon icon to use in the tile shown to the user. * @param resultExecutor an executor to run the callback on * @param resultCallback callback to indicate the {@link RequestResult}. - * @return whether the request was successfully sent. * * @see android.service.quicksettings.TileService */ - @RequestAnswer - public int requestAddTileService( + public void requestAddTileService( @NonNull ComponentName tileServiceComponentName, @NonNull CharSequence tileLabel, @NonNull Icon icon, @@ -644,14 +640,16 @@ public class StatusBarManager { Objects.requireNonNull(resultExecutor); Objects.requireNonNull(resultCallback); if (!tileServiceComponentName.getPackageName().equals(mContext.getPackageName())) { - return TILE_ADD_REQUEST_ANSWER_FAILED_MISMATCHED_PACKAGE; + resultExecutor.execute( + () -> resultCallback.accept(TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE)); + return; } int userId = mContext.getUserId(); RequestResultCallback callbackProxy = new RequestResultCallback(resultExecutor, resultCallback); IStatusBarService svc = getService(); try { - return svc.requestAddTile( + svc.requestAddTile( tileServiceComponentName, tileLabel, icon, @@ -661,7 +659,6 @@ public class StatusBarManager { } catch (RemoteException ex) { ex.rethrowFromSystemServer(); } - return TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON; } /** @hide */ diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 92031b4e14ae2..49c32be9b43a1 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -160,5 +160,5 @@ interface IStatusBarService */ void suppressAmbientDisplay(boolean suppress); - int requestAddTile(in ComponentName componentName, in CharSequence label, in Icon icon, int userId, in IAddTileResultCallback callback); + void requestAddTile(in ComponentName componentName, in CharSequence label, in Icon icon, int userId, in IAddTileResultCallback callback); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt index fe1a619f29af2..3b85e5dc1ce00 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt @@ -52,7 +52,7 @@ class TileServiceRequestController constructor( internal const val DONT_ADD_TILE = StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED internal const val TILE_ALREADY_ADDED = StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED - internal const val DISMISSED = 3 + internal const val DISMISSED = StatusBarManager.TILE_ADD_REQUEST_RESULT_DIALOG_DISMISSED } private val commandQueueCallback = object : CommandQueue.Callbacks { diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 7ac9110dd3cf2..3f0f01156d6f5 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -1689,7 +1689,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override - public int requestAddTile( + public void requestAddTile( @NonNull ComponentName componentName, @NonNull CharSequence label, @NonNull Icon icon, @@ -1710,13 +1710,23 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // Check current user if (userId != currentUser) { - return StatusBarManager.TILE_ADD_REQUEST_ANSWER_FAILED_NOT_CURRENT_USER; + try { + callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER); + } catch (RemoteException e) { + Slog.e(TAG, "requestAddTile", e); + } + return; } // We've checked that the package, component name and uid all match. ResolveInfo r = isComponentValidTileService(componentName, userId); if (r == null) { - return StatusBarManager.TILE_ADD_REQUEST_ANSWER_FAILED_BAD_COMPONENT; + try { + callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_BAD_COMPONENT); + } catch (RemoteException e) { + Slog.e(TAG, "requestAddTile", e); + } + return; } IAddTileResultCallback proxyCallback = new IAddTileResultCallback.Stub() { @@ -1734,12 +1744,16 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D if (mBar != null) { try { mBar.requestAddTile(componentName, appName, label, icon, proxyCallback); - return StatusBarManager.TILE_ADD_REQUEST_ANSWER_SUCCESS; } catch (RemoteException e) { Slog.e(TAG, "requestAddTile", e); } + return; + } + try { + callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE); + } catch (RemoteException e) { + Slog.e(TAG, "requestAddTile", e); } - return StatusBarManager.TILE_ADD_REQUEST_ANSWER_FAILED_UNKNOWN_REASON; } public String[] getStatusBarIcons() { From 61792c4741bf034c792143e28c50e99eb720ce6d Mon Sep 17 00:00:00 2001 From: Fabian Kozynski Date: Tue, 14 Sep 2021 10:57:21 -0400 Subject: [PATCH 2/2] Add extra security checks for TileService API When requesting a tile to be added, the TileService should be exported. Also, the requesting application should be in the foreground, so the user cannot get unexpected requests. Test: CTS tests Test: manual Fixes: 199770909 Change-Id: I2e131bf2fd3de91767e7604768bc0141ef3cd427 --- core/api/current.txt | 3 ++- core/java/android/app/StatusBarManager.java | 14 +++++++++++--- .../server/statusbar/StatusBarManagerService.java | 15 ++++++++++++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 46afb9d0bbe35..644e094d4c931 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -6699,10 +6699,11 @@ package android.app { public class StatusBarManager { method public void requestAddTileService(@NonNull android.content.ComponentName, @NonNull CharSequence, @NonNull android.graphics.drawable.Icon, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); + field public static final int TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND = 1004; // 0x3ec field public static final int TILE_ADD_REQUEST_ERROR_BAD_COMPONENT = 1002; // 0x3ea field public static final int TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE = 1000; // 0x3e8 field public static final int TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER = 1003; // 0x3eb - field public static final int TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE = 1004; // 0x3ec + field public static final int TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE = 1005; // 0x3ed field public static final int TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS = 1001; // 0x3e9 field public static final int TILE_ADD_REQUEST_RESULT_TILE_ADDED = 2; // 0x2 field public static final int TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED = 1; // 0x1 diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 53dcef75da005..64f89bc75ff66 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -245,7 +245,7 @@ public class StatusBarManager { public static final int TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS = TILE_ADD_REQUEST_FIRST_ERROR_CODE + 1; /** - * Indicates that the component does not match an enabled + * Indicates that the component does not match an enabled exported * {@link android.service.quicksettings.TileService} for the current user. */ public static final int TILE_ADD_REQUEST_ERROR_BAD_COMPONENT = @@ -255,12 +255,17 @@ public class StatusBarManager { */ public static final int TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER = TILE_ADD_REQUEST_FIRST_ERROR_CODE + 3; + /** + * Indicates that the requesting application is not in the foreground. + */ + public static final int TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND = + TILE_ADD_REQUEST_FIRST_ERROR_CODE + 4; /** * The request could not be processed because no fulfilling service was found. This could be * a temporary issue (for example, SystemUI has crashed). */ public static final int TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE = - TILE_ADD_REQUEST_FIRST_ERROR_CODE + 4; + TILE_ADD_REQUEST_FIRST_ERROR_CODE + 5; /** @hide */ @IntDef(prefix = {"TILE_ADD_REQUEST"}, value = { @@ -271,6 +276,7 @@ public class StatusBarManager { TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS, TILE_ADD_REQUEST_ERROR_BAD_COMPONENT, TILE_ADD_REQUEST_ERROR_NOT_CURRENT_USER, + TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND, TILE_ADD_REQUEST_ERROR_NO_STATUS_BAR_SERVICE }) @Retention(RetentionPolicy.SOURCE) @@ -616,7 +622,9 @@ public class StatusBarManager { * *

* The user for which this will be added is determined from the {@link Context} used to retrieve - * this service, and must match the current user. + * this service, and must match the current user. The requesting application must be in the + * foreground ({@link ActivityManager.RunningAppProcessInfo#IMPORTANCE_FOREGROUND} + * and the {@link android.service.quicksettings.TileService} must be exported. * * @param tileServiceComponentName {@link ComponentName} of the * {@link android.service.quicksettings.TileService} for the request. diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 3f0f01156d6f5..00d01e13ec459 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -23,6 +23,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityThread; import android.app.ITransientNotificationCallback; @@ -1720,7 +1721,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // We've checked that the package, component name and uid all match. ResolveInfo r = isComponentValidTileService(componentName, userId); - if (r == null) { + if (r == null || !r.serviceInfo.exported) { try { callback.onTileRequest(StatusBarManager.TILE_ADD_REQUEST_ERROR_BAD_COMPONENT); } catch (RemoteException e) { @@ -1729,6 +1730,18 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D return; } + final int procState = mActivityManagerInternal.getUidProcessState(callingUid); + if (ActivityManager.RunningAppProcessInfo.procStateToImportance(procState) + != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { + try { + callback.onTileRequest( + StatusBarManager.TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND); + } catch (RemoteException e) { + Slog.e(TAG, "requestAddTile", e); + } + return; + } + IAddTileResultCallback proxyCallback = new IAddTileResultCallback.Stub() { @Override public void onTileRequest(int i) throws RemoteException {