summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-02-13 21:00:44 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-02-13 21:00:44 +0000
commita0658f5c94789aa728600314992e3213c066cff3 (patch)
tree0a16354825cf70e55beaaaf5d981501b2c0eb360
parent0c510f5025664af5165a91013e06b39ce86d66f5 (diff)
parent8fcba84789dc59b045032d40771f7cdc93924faa (diff)
downloadbase-a0658f5c94789aa728600314992e3213c066cff3.tar.gz
Merge cherrypicks of ['googleplex-android-review.googlesource.com/20322453', 'googleplex-android-review.googlesource.com/20860033', 'googleplex-android-review.googlesource.com/20641928', 'googleplex-android-review.googlesource.com/20912010', 'googleplex-android-review.googlesource.com/20900583', 'googleplex-android-review.googlesource.com/20924783', 'googleplex-android-review.googlesource.com/21018677', 'googleplex-android-review.googlesource.com/21096603', 'googleplex-android-review.googlesource.com/21127326', 'googleplex-android-review.googlesource.com/21017683'] into sc-v2-platform-release.android-platform-12.1.0_r14
Change-Id: I1ed6f1c157680fdb6bd3b3ebd8215b1b441acc83
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java25
-rw-r--r--core/java/android/app/ActivityOptions.java10
-rw-r--r--core/java/android/app/BroadcastOptions.java25
-rw-r--r--core/java/android/app/ComponentOptions.java83
-rw-r--r--core/java/android/content/Intent.java2
-rw-r--r--core/java/android/content/IntentSender.java41
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java15
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java34
-rw-r--r--services/core/java/com/android/server/am/PendingIntentRecord.java22
-rw-r--r--services/core/java/com/android/server/location/provider/LocationProviderManager.java1
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java14
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java11
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java22
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java10
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java24
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/AppTaskImpl.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java33
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java59
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java47
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java9
22 files changed, 442 insertions, 54 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index c9b33aa4dafc..1e78277642dc 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -56,6 +56,7 @@ import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
@@ -316,6 +317,8 @@ public class AlarmManagerService extends SystemService {
private final SparseBooleanArray mPendingSendNextAlarmClockChangedForUser =
new SparseBooleanArray();
private boolean mNextAlarmClockMayChange;
+ ActivityOptions mActivityOptsRestrictBal = ActivityOptions.makeBasic();
+ BroadcastOptions mBroadcastOptsRestrictBal = BroadcastOptions.makeBasic();
@GuardedBy("mLock")
private final Runnable mAlarmClockUpdater = () -> mNextAlarmClockMayChange = true;
@@ -1610,6 +1613,11 @@ public class AlarmManagerService extends SystemService {
@Override
public void onStart() {
mInjector.init();
+ mOptsWithFgs.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ mOptsWithoutFgs.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ mOptsTimeBroadcast.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ mActivityOptsRestrictBal.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ mBroadcastOptsRestrictBal.setPendingIntentBackgroundActivityLaunchAllowed(false);
mMetricsHelper = new MetricsHelper(getContext(), mLock);
mListenerDeathRecipient = new IBinder.DeathRecipient() {
@@ -4301,6 +4309,14 @@ public class AlarmManagerService extends SystemService {
return alarm.creatorUid;
}
+ private Bundle getAlarmOperationBundle(Alarm alarm) {
+ if (alarm.mIdleOptions != null) {
+ return alarm.mIdleOptions;
+ } else if (alarm.operation.isActivity()) {
+ return mActivityOptsRestrictBal.toBundle();
+ }
+ return mBroadcastOptsRestrictBal.toBundle();
+ }
@VisibleForTesting
class AlarmHandler extends Handler {
@@ -4339,7 +4355,11 @@ public class AlarmManagerService extends SystemService {
for (int i = 0; i < triggerList.size(); i++) {
Alarm alarm = triggerList.get(i);
try {
- alarm.operation.send();
+ // Disallow AlarmManager to start random background activity.
+ final Bundle bundle = getAlarmOperationBundle(alarm);
+ alarm.operation.send(/* context */ null, /* code */0, /* intent */
+ null, /* onFinished */null, /* handler */
+ null, /* requiredPermission */ null, bundle);
} catch (PendingIntent.CanceledException e) {
if (alarm.repeatInterval > 0) {
// This IntentSender is no longer valid, but this
@@ -4903,9 +4923,10 @@ public class AlarmManagerService extends SystemService {
mSendCount++;
try {
+ final Bundle bundle = getAlarmOperationBundle(alarm);
alarm.operation.send(getContext(), 0,
mBackgroundIntent.putExtra(Intent.EXTRA_ALARM_COUNT, alarm.count),
- mDeliveryTracker, mHandler, null, alarm.mIdleOptions);
+ mDeliveryTracker, mHandler, null, bundle);
} catch (PendingIntent.CanceledException e) {
if (alarm.repeatInterval > 0) {
// This IntentSender is no longer valid, but this
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index e76f89ce9461..3a813224f6d8 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -69,7 +69,7 @@ import java.util.ArrayList;
* {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
* Context.startActivity(Intent, Bundle)} and related methods.
*/
-public class ActivityOptions {
+public class ActivityOptions extends ComponentOptions {
private static final String TAG = "ActivityOptions";
/**
@@ -1081,13 +1081,12 @@ public class ActivityOptions {
}
private ActivityOptions() {
+ super();
}
/** @hide */
public ActivityOptions(Bundle opts) {
- // If the remote side sent us bad parcelables, they won't get the
- // results they want, which is their loss.
- opts.setDefusable(true);
+ super(opts);
mPackageName = opts.getString(KEY_PACKAGE_NAME);
try {
@@ -1832,8 +1831,9 @@ public class ActivityOptions {
* object; you must not modify it, but can supply it to the startActivity
* methods that take an options Bundle.
*/
+ @Override
public Bundle toBundle() {
- Bundle b = new Bundle();
+ Bundle b = super.toBundle();
if (mPackageName != null) {
b.putString(KEY_PACKAGE_NAME, mPackageName);
}
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index bd7162c1bf3b..38c94ec20670 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -34,7 +34,7 @@ import android.os.PowerExemptionManager.TempAllowListType;
* {@hide}
*/
@SystemApi
-public class BroadcastOptions {
+public class BroadcastOptions extends ComponentOptions {
private long mTemporaryAppAllowlistDuration;
private @TempAllowListType int mTemporaryAppAllowlistType;
private @ReasonCode int mTemporaryAppAllowlistReasonCode;
@@ -108,12 +108,14 @@ public class BroadcastOptions {
}
private BroadcastOptions() {
+ super();
resetTemporaryAppAllowlist();
}
/** @hide */
@TestApi
public BroadcastOptions(@NonNull Bundle opts) {
+ super(opts);
// Match the logic in toBundle().
if (opts.containsKey(KEY_TEMPORARY_APP_ALLOWLIST_DURATION)) {
mTemporaryAppAllowlistDuration = opts.getLong(KEY_TEMPORARY_APP_ALLOWLIST_DURATION);
@@ -191,6 +193,24 @@ public class BroadcastOptions {
}
/**
+ * Set PendingIntent activity is allowed to be started in the background if the caller
+ * can start background activities.
+ * @hide
+ */
+ public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) {
+ super.setPendingIntentBackgroundActivityLaunchAllowed(allowed);
+ }
+
+ /**
+ * Get PendingIntent activity is allowed to be started in the background if the caller
+ * can start background activities.
+ * @hide
+ */
+ public boolean isPendingIntentBackgroundActivityLaunchAllowed() {
+ return super.isPendingIntentBackgroundActivityLaunchAllowed();
+ }
+
+ /**
* Return {@link #setTemporaryAppAllowlist}.
* @hide
*/
@@ -308,8 +328,9 @@ public class BroadcastOptions {
* object; you must not modify it, but can supply it to the sendBroadcast
* methods that take an options Bundle.
*/
+ @Override
public Bundle toBundle() {
- Bundle b = new Bundle();
+ Bundle b = super.toBundle();
if (isTemporaryAppAllowlistSet()) {
b.putLong(KEY_TEMPORARY_APP_ALLOWLIST_DURATION, mTemporaryAppAllowlistDuration);
b.putInt(KEY_TEMPORARY_APP_ALLOWLIST_TYPE, mTemporaryAppAllowlistType);
diff --git a/core/java/android/app/ComponentOptions.java b/core/java/android/app/ComponentOptions.java
new file mode 100644
index 000000000000..86efd622cb82
--- /dev/null
+++ b/core/java/android/app/ComponentOptions.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+public class ComponentOptions {
+
+ /**
+ * Default value for KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED.
+ * @hide
+ **/
+ public static final boolean PENDING_INTENT_BAL_ALLOWED_DEFAULT = true;
+
+ /**
+ * PendingIntent caller allows activity start even if PendingIntent creator is in background.
+ * This only works if the PendingIntent caller is allowed to start background activities,
+ * for example if it's in the foreground, or has BAL permission.
+ * @hide
+ */
+ public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED =
+ "android.pendingIntent.backgroundActivityAllowed";
+
+ private boolean mPendingIntentBalAllowed = PENDING_INTENT_BAL_ALLOWED_DEFAULT;
+
+ ComponentOptions() {
+ }
+
+ ComponentOptions(Bundle opts) {
+ // If the remote side sent us bad parcelables, they won't get the
+ // results they want, which is their loss.
+ opts.setDefusable(true);
+ setPendingIntentBackgroundActivityLaunchAllowed(
+ opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
+ PENDING_INTENT_BAL_ALLOWED_DEFAULT));
+ }
+
+ /**
+ * Set PendingIntent activity is allowed to be started in the background if the caller
+ * can start background activities.
+ *
+ * @hide
+ */
+ public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) {
+ mPendingIntentBalAllowed = allowed;
+ }
+
+ /**
+ * Get PendingIntent activity is allowed to be started in the background if the caller
+ * can start background activities.
+ *
+ * @hide
+ */
+ public boolean isPendingIntentBackgroundActivityLaunchAllowed() {
+ return mPendingIntentBalAllowed;
+ }
+
+ /**
+ * @hide
+ */
+ public Bundle toBundle() {
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed);
+ return bundle;
+ }
+}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 35794d79b49d..6224758ce71a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -11011,7 +11011,7 @@ public class Intent implements Parcelable, Cloneable {
private void toUriInner(StringBuilder uri, String scheme, String defAction,
String defPackage, int flags) {
if (scheme != null) {
- uri.append("scheme=").append(scheme).append(';');
+ uri.append("scheme=").append(Uri.encode(scheme)).append(';');
}
if (mAction != null && !mAction.equals(defAction)) {
uri.append("action=").append(Uri.encode(mAction)).append(';');
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index b1252fd0b21f..49d3cac63124 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -19,6 +19,7 @@ package android.content;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.PendingIntentInfo;
+import android.app.ActivityOptions;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.Handler;
@@ -158,7 +159,7 @@ public class IntentSender implements Parcelable {
*/
public void sendIntent(Context context, int code, Intent intent,
OnFinished onFinished, Handler handler) throws SendIntentException {
- sendIntent(context, code, intent, onFinished, handler, null);
+ sendIntent(context, code, intent, onFinished, handler, null, null /* options */);
}
/**
@@ -190,6 +191,42 @@ public class IntentSender implements Parcelable {
public void sendIntent(Context context, int code, Intent intent,
OnFinished onFinished, Handler handler, String requiredPermission)
throws SendIntentException {
+ sendIntent(context, code, intent, onFinished, handler, requiredPermission,
+ null /* options */);
+ }
+
+ /**
+ * Perform the operation associated with this IntentSender, allowing the
+ * caller to specify information about the Intent to use and be notified
+ * when the send has completed.
+ *
+ * @param context The Context of the caller. This may be null if
+ * <var>intent</var> is also null.
+ * @param code Result code to supply back to the IntentSender's target.
+ * @param intent Additional Intent data. See {@link Intent#fillIn
+ * Intent.fillIn()} for information on how this is applied to the
+ * original Intent. Use null to not modify the original Intent.
+ * @param onFinished The object to call back on when the send has
+ * completed, or null for no callback.
+ * @param handler Handler identifying the thread on which the callback
+ * should happen. If null, the callback will happen from the thread
+ * pool of the process.
+ * @param requiredPermission Name of permission that a recipient of the PendingIntent
+ * is required to hold. This is only valid for broadcast intents, and
+ * corresponds to the permission argument in
+ * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}.
+ * If null, no permission is required.
+ * @param options Additional options the caller would like to provide to modify the sending
+ * behavior. May be built from an {@link ActivityOptions} to apply to an activity start.
+ *
+ * @throws SendIntentException Throws CanceledIntentException if the IntentSender
+ * is no longer allowing more intents to be sent through it.
+ * @hide
+ */
+ public void sendIntent(Context context, int code, Intent intent,
+ OnFinished onFinished, Handler handler, String requiredPermission,
+ @Nullable Bundle options)
+ throws SendIntentException {
try {
String resolvedType = intent != null ?
intent.resolveTypeIfNeeded(context.getContentResolver())
@@ -199,7 +236,7 @@ public class IntentSender implements Parcelable {
onFinished != null
? new FinishedDispatcher(this, onFinished, handler)
: null,
- requiredPermission, null);
+ requiredPermission, options);
if (res < 0) {
throw new SendIntentException();
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index a8672ff38e9d..8c80dfb94d53 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3513,8 +3513,7 @@ public class AccountManagerService
Bundle.setDefusable(result, true);
mNumResults++;
Intent intent = null;
- if (result != null
- && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
+ if (result != null) {
if (!checkKeyIntent(
Binder.getCallingUid(),
result)) {
@@ -4873,8 +4872,10 @@ public class AccountManagerService
EventLog.writeEvent(0x534e4554, "250588548", authUid, "");
return false;
}
-
Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
+ if (intent == null) {
+ return true;
+ }
// Explicitly set an empty ClipData to ensure that we don't offer to
// promote any Uris contained inside for granting purposes
if (intent.getClipData() == null) {
@@ -4927,7 +4928,10 @@ public class AccountManagerService
p.recycle();
Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
Intent simulateIntent = simulateBundle.getParcelable(AccountManager.KEY_INTENT);
- return (intent.filterEquals(simulateIntent));
+ if (intent == null) {
+ return (simulateIntent == null);
+ }
+ return intent.filterEquals(simulateIntent);
}
private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
@@ -5072,8 +5076,7 @@ public class AccountManagerService
}
}
}
- if (result != null
- && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
+ if (result != null) {
if (!checkKeyIntent(
Binder.getCallingUid(),
result)) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index bad728a86c00..0007217b27dc 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3201,6 +3201,11 @@ public final class ActiveServices {
throw new SecurityException("BIND_EXTERNAL_SERVICE failed, "
+ className + " is not an isolatedProcess");
}
+ if (AppGlobals.getPackageManager().getPackageUid(callingPackage,
+ 0, userId) != callingUid) {
+ throw new SecurityException("BIND_EXTERNAL_SERVICE failed, "
+ + "calling package not owned by calling UID ");
+ }
// Run the service under the calling package's application.
ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d8508eac22ed..336433bbad89 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13849,6 +13849,17 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new SecurityException(msg);
}
}
+ if (!Build.IS_DEBUGGABLE && callingUid != ROOT_UID && callingUid != SHELL_UID
+ && callingUid != SYSTEM_UID && !hasActiveInstrumentationLocked(callingPid)) {
+ // If it's not debug build and not called from root/shell/system uid, reject it.
+ final String msg = "Permission Denial: instrumentation test "
+ + className + " from pid=" + callingPid + ", uid=" + callingUid
+ + ", pkgName=" + getPackageNameByPid(callingPid)
+ + " not allowed because it's not started from SHELL";
+ Slog.wtfQuiet(TAG, msg);
+ reportStartInstrumentationFailureLocked(watcher, className, msg);
+ throw new SecurityException(msg);
+ }
ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
activeInstr.mClass = className;
@@ -13947,6 +13958,29 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ @GuardedBy("this")
+ private boolean hasActiveInstrumentationLocked(int pid) {
+ if (pid == 0) {
+ return false;
+ }
+ synchronized (mPidsSelfLocked) {
+ ProcessRecord process = mPidsSelfLocked.get(pid);
+ return process != null && process.getActiveInstrumentation() != null;
+ }
+ }
+
+ private String getPackageNameByPid(int pid) {
+ synchronized (mPidsSelfLocked) {
+ final ProcessRecord app = mPidsSelfLocked.get(pid);
+
+ if (app != null && app.info != null) {
+ return app.info.packageName;
+ }
+
+ return null;
+ }
+ }
+
private boolean isCallerShell() {
final int callingUid = Binder.getCallingUid();
return callingUid == SHELL_UID || callingUid == ROOT_UID;
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 33f745ef211f..d5981bb60215 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -310,6 +310,25 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
requiredPermission, null, null, 0, 0, 0, options);
}
+ /**
+ * Return true if the activity options allows PendingIntent to use caller's BAL permission.
+ */
+ public static boolean isPendingIntentBalAllowedByCaller(
+ @Nullable ActivityOptions activityOptions) {
+ if (activityOptions == null) {
+ return ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT;
+ }
+ return isPendingIntentBalAllowedByCaller(activityOptions.toBundle());
+ }
+
+ private static boolean isPendingIntentBalAllowedByCaller(@Nullable Bundle options) {
+ if (options == null) {
+ return ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT;
+ }
+ return options.getBoolean(ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
+ ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT);
+ }
+
public int sendInner(int code, Intent intent, String resolvedType, IBinder allowlistToken,
IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo,
String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) {
@@ -436,7 +455,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
// temporarily allow receivers and services to open activities from background if the
// PendingIntent.send() caller was foreground at the time of sendInner() call
final boolean allowTrampoline = uid != callingUid
- && controller.mAtmInternal.isUidForeground(callingUid);
+ && controller.mAtmInternal.isUidForeground(callingUid)
+ && isPendingIntentBalAllowedByCaller(options);
// note: we on purpose don't pass in the information about the PendingIntent's creator,
// like pid or ProcessRecord, to the ActivityTaskManagerInternal calls below, because
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 9ed63b5ce2da..eda5a94258c2 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -281,6 +281,7 @@ public class LocationProviderManager extends
public void deliverOnFlushComplete(int requestCode) throws PendingIntent.CanceledException {
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setDontSendToRestrictedApps(true);
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_FLUSH_COMPLETE, requestCode),
null, null, null, options.toBundle());
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 72b75f3e80d1..1a0fa602ea48 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -98,6 +98,8 @@ public class PreferencesHelper implements RankingConfig {
@VisibleForTesting
static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 5000;
+ @VisibleForTesting
+ static final int NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT = 6000;
private static final int NOTIFICATION_PREFERENCES_PULL_LIMIT = 1000;
private static final int NOTIFICATION_CHANNEL_PULL_LIMIT = 2000;
@@ -239,6 +241,7 @@ public class PreferencesHelper implements RankingConfig {
}
}
boolean skipWarningLogged = false;
+ boolean skipGroupWarningLogged = false;
boolean hasSAWPermission = false;
if (upgradeForBubbles && uid != UNKNOWN_UID) {
hasSAWPermission = mAppOps.noteOpNoThrow(
@@ -289,6 +292,14 @@ public class PreferencesHelper implements RankingConfig {
String tagName = parser.getName();
// Channel groups
if (TAG_GROUP.equals(tagName)) {
+ if (r.groups.size() >= NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT) {
+ if (!skipGroupWarningLogged) {
+ Slog.w(TAG, "Skipping further groups for " + r.pkg
+ + "; app has too many");
+ skipGroupWarningLogged = true;
+ }
+ continue;
+ }
String id = parser.getAttributeValue(null, ATT_ID);
CharSequence groupName = parser.getAttributeValue(null,
ATT_NAME);
@@ -798,6 +809,9 @@ public class PreferencesHelper implements RankingConfig {
}
if (fromTargetApp) {
group.setBlocked(false);
+ if (r.groups.size() >= NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT) {
+ throw new IllegalStateException("Limit exceed; cannot create more groups");
+ }
}
final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
if (oldGroup != null) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 708b2129ad29..2ca3e8f1bc1b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PackageDeleteObserver;
@@ -1243,7 +1244,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
PackageInstaller.STATUS_PENDING_USER_ACTION);
fillIn.putExtra(Intent.EXTRA_INTENT, intent);
try {
- mTarget.sendIntent(mContext, 0, fillIn, null, null);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ mTarget.sendIntent(mContext, 0, fillIn, null /* onFinished*/,
+ null /* handler */, null /* requiredPermission */, options.toBundle());
} catch (SendIntentException ignored) {
}
}
@@ -1268,7 +1272,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
PackageManager.deleteStatusToString(returnCode, msg));
fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
try {
- mTarget.sendIntent(mContext, 0, fillIn, null, null);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ mTarget.sendIntent(mContext, 0, fillIn, null /* onFinished*/,
+ null /* handler */, null /* requiredPermission */, options.toBundle());
} catch (SendIntentException ignored) {
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3ddcf17d0a47..1137fc5b5a86 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -50,6 +50,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyEventLogger;
@@ -1872,7 +1873,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
} else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
try {
- mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ mStatusReceiver.sendIntent(mContext, 0, intent,
+ null /* onFinished*/, null /* handler */,
+ null /* requiredPermission */, options.toBundle());
} catch (IntentSender.SendIntentException ignore) {
}
} else { // failure, let's forward and clean up this session.
@@ -4375,7 +4380,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION);
fillIn.putExtra(Intent.EXTRA_INTENT, intent);
try {
- target.sendIntent(context, 0, fillIn, null, null);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ target.sendIntent(context, 0, fillIn, null /* onFinished */,
+ null /* handler */, null /* requiredPermission */, options.toBundle());
} catch (IntentSender.SendIntentException ignored) {
}
}
@@ -4418,7 +4426,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
try {
- target.sendIntent(context, 0, fillIn, null, null);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ target.sendIntent(context, 0, fillIn, null /* onFinished */,
+ null /* handler */, null /* requiredPermission */, options.toBundle());
} catch (IntentSender.SendIntentException ignored) {
}
}
@@ -4443,7 +4454,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Staging Image Not Ready");
}
try {
- target.sendIntent(context, 0, intent, null, null);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ target.sendIntent(context, 0, intent, null /* onFinished */,
+ null /* handler */, null /* requiredPermission */, options.toBundle());
} catch (IntentSender.SendIntentException ignored) {
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 12e594716410..ac806e1e9c27 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9204,7 +9204,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (pi != null) {
try {
- pi.sendIntent(null, success ? 1 : 0, null, null, null);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ pi.sendIntent(null, success ? 1 : 0, null /* intent */, null /* onFinished*/,
+ null /* handler */, null /* requiredPermission */, options.toBundle());
} catch (SendIntentException e) {
Slog.w(TAG, e);
}
@@ -16369,7 +16372,10 @@ public class PackageManagerService extends IPackageManager.Stub
fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
PackageManager.installStatusToPublicStatus(returnCode));
try {
- target.sendIntent(context, 0, fillIn, null, null);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
+ target.sendIntent(context, 0, fillIn, null /* onFinished*/,
+ null /* handler */, null /* requiredPermission */, options.toBundle());
} catch (SendIntentException ignored) {
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 436a325559e6..6ba77cd76d8b 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -989,6 +989,10 @@ class ActivityStarter {
abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
callingPackage);
+ // Merge the two options bundles, while realCallerOptions takes precedence.
+ ActivityOptions checkedOptions = options != null
+ ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
+
boolean restrictedBgActivity = false;
if (!abort) {
try {
@@ -997,15 +1001,12 @@ class ActivityStarter {
restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
request.originatingPendingIntent, request.allowBackgroundActivityStart,
- intent);
+ intent, checkedOptions);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
}
- // Merge the two options bundles, while realCallerOptions takes precedence.
- ActivityOptions checkedOptions = options != null
- ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
if (request.allowPendingRemoteAnimationRegistryLookup) {
checkedOptions = mService.getActivityStartController()
.getPendingRemoteAnimationRegistry()
@@ -1247,7 +1248,7 @@ class ActivityStarter {
boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
final String callingPackage, int realCallingUid, int realCallingPid,
WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart, Intent intent) {
+ boolean allowBackgroundActivityStart, Intent intent, ActivityOptions checkedOptions) {
// don't abort for the most important UIDs
final int callingAppId = UserHandle.getAppId(callingUid);
if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
@@ -1318,9 +1319,12 @@ class ActivityStarter {
? isCallingUidPersistentSystemProcess
: (realCallingAppId == Process.SYSTEM_UID)
|| realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
- if (realCallingUid != callingUid) {
- // don't abort if the realCallingUid has a visible window
- // TODO(b/171459802): We should check appSwitchAllowed also
+
+ // Legacy behavior allows to use caller foreground state to bypass BAL restriction.
+ final boolean balAllowedByPiSender =
+ PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions);
+
+ if (balAllowedByPiSender && realCallingUid != callingUid) {
if (realCallingUidHasAnyVisibleWindow) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
@@ -1393,9 +1397,9 @@ class ActivityStarter {
// If we don't have callerApp at this point, no caller was provided to startActivity().
// That's the case for PendingIntent-based starts, since the creator's process might not be
// up and alive. If that's the case, we retrieve the WindowProcessController for the send()
- // caller, so that we can make the decision based on its state.
+ // caller if caller allows, so that we can make the decision based on its state.
int callerAppUid = callingUid;
- if (callerApp == null) {
+ if (callerApp == null && balAllowedByPiSender) {
callerApp = mService.getProcessController(realCallingPid, realCallingUid);
callerAppUid = realCallingUid;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f17c9f9c0a53..0965709454f6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2105,7 +2105,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final ActivityStarter starter = getActivityStartController().obtainStarter(
null /* intent */, "moveTaskToFront");
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
- -1, callerApp, null, false, null)) {
+ -1, callerApp, null, false, null, null)) {
if (!isBackgroundActivityStartsEnabled()) {
return;
}
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 3c9adfb9c4bd..ccd525b63863 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -108,7 +108,7 @@ class AppTaskImpl extends IAppTask.Stub {
final ActivityStarter starter = mService.getActivityStartController().obtainStarter(
null /* intent */, "moveToFront");
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,
- callingPackage, -1, -1, callerApp, null, false, null)) {
+ callingPackage, -1, -1, callerApp, null, false, null, null)) {
if (!mService.isBackgroundActivityStartsEnabled()) {
return;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 67a40ac9dfa4..b938f4f0171f 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3496,12 +3496,39 @@ class Task extends TaskFragment {
if (info.topActivityInfo != null
&& task.effectiveUid != info.topActivityInfo.applicationInfo.uid) {
- info.topActivity = null;
- info.topActivityInfo = null;
+ // Making a copy to prevent eliminating the info in the original ActivityRecord.
+ info.topActivityInfo = new ActivityInfo(info.topActivityInfo);
+ info.topActivityInfo.applicationInfo =
+ new ApplicationInfo(info.topActivityInfo.applicationInfo);
+
+ // Strip the sensitive info.
+ info.topActivity = new ComponentName("", "");
+ info.topActivityInfo.packageName = "";
+ info.topActivityInfo.taskAffinity = "";
+ info.topActivityInfo.processName = "";
+ info.topActivityInfo.name = "";
+ info.topActivityInfo.parentActivityName = "";
+ info.topActivityInfo.targetActivity = "";
+ info.topActivityInfo.splitName = "";
+ info.topActivityInfo.applicationInfo.className = "";
+ info.topActivityInfo.applicationInfo.credentialProtectedDataDir = "";
+ info.topActivityInfo.applicationInfo.dataDir = "";
+ info.topActivityInfo.applicationInfo.deviceProtectedDataDir = "";
+ info.topActivityInfo.applicationInfo.manageSpaceActivityName = "";
+ info.topActivityInfo.applicationInfo.nativeLibraryDir = "";
+ info.topActivityInfo.applicationInfo.nativeLibraryRootDir = "";
+ info.topActivityInfo.applicationInfo.processName = "";
+ info.topActivityInfo.applicationInfo.publicSourceDir = "";
+ info.topActivityInfo.applicationInfo.scanPublicSourceDir = "";
+ info.topActivityInfo.applicationInfo.scanSourceDir = "";
+ info.topActivityInfo.applicationInfo.sourceDir = "";
+ info.topActivityInfo.applicationInfo.taskAffinity = "";
+ info.topActivityInfo.applicationInfo.name = "";
+ info.topActivityInfo.applicationInfo.packageName = "";
}
if (task.effectiveUid != baseActivityUid) {
- info.baseActivity = null;
+ info.baseActivity = new ComponentName("", "");
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 32d9247216c4..e2ac889c8566 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -109,6 +109,7 @@ import static org.mockito.Mockito.times;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
@@ -552,13 +553,23 @@ public class AlarmManagerServiceTest {
private PendingIntent getNewMockPendingIntent() {
- return getNewMockPendingIntent(TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+ return getNewMockPendingIntent(false);
+ }
+
+ private PendingIntent getNewMockPendingIntent(boolean isActivity) {
+ return getNewMockPendingIntent(TEST_CALLING_UID, TEST_CALLING_PACKAGE, isActivity);
}
private PendingIntent getNewMockPendingIntent(int creatorUid, String creatorPackage) {
+ return getNewMockPendingIntent(creatorUid, creatorPackage, false);
+ }
+
+ private PendingIntent getNewMockPendingIntent(int creatorUid, String creatorPackage,
+ boolean isActivity) {
final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS);
when(mockPi.getCreatorUid()).thenReturn(creatorUid);
when(mockPi.getCreatorPackage()).thenReturn(creatorPackage);
+ when(mockPi.isActivity()).thenReturn(isActivity);
return mockPi;
}
@@ -2801,21 +2812,53 @@ public class AlarmManagerServiceTest {
anyString()));
}
- @Test
- public void idleOptionsSentOnExpiration() throws Exception {
+ private void optionsSentOnExpiration(boolean isActivity, Bundle idleOptions)
+ throws Exception {
final long triggerTime = mNowElapsedTest + 5000;
- final PendingIntent alarmPi = getNewMockPendingIntent();
- final Bundle idleOptions = new Bundle();
- idleOptions.putChar("TEST_CHAR_KEY", 'x');
- idleOptions.putInt("TEST_INT_KEY", 53);
+ final PendingIntent alarmPi = getNewMockPendingIntent(isActivity);
setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, 0, alarmPi, 0, 0, TEST_CALLING_UID,
idleOptions);
mNowElapsedTest = mTestTimer.getElapsed();
mTestTimer.expire();
+ ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class),
- any(), any(Handler.class), isNull(), eq(idleOptions));
+ any(), any(Handler.class), isNull(), bundleCaptor.capture());
+ if (idleOptions != null) {
+ assertEquals(idleOptions, bundleCaptor.getValue());
+ } else {
+ assertFalse("BAL flag needs to be false in alarm manager",
+ bundleCaptor.getValue().getBoolean(
+ ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
+ true));
+ }
+ }
+
+ @Test
+ public void activityIdleOptionsSentOnExpiration() throws Exception {
+ final Bundle idleOptions = new Bundle();
+ idleOptions.putChar("TEST_CHAR_KEY", 'x');
+ idleOptions.putInt("TEST_INT_KEY", 53);
+ optionsSentOnExpiration(true, idleOptions);
+ }
+
+ @Test
+ public void broadcastIdleOptionsSentOnExpiration() throws Exception {
+ final Bundle idleOptions = new Bundle();
+ idleOptions.putChar("TEST_CHAR_KEY", 'x');
+ idleOptions.putInt("TEST_INT_KEY", 53);
+ optionsSentOnExpiration(false, idleOptions);
+ }
+
+ @Test
+ public void emptyActivityOptionsSentOnExpiration() throws Exception {
+ optionsSentOnExpiration(true, null);
+ }
+
+ @Test
+ public void emptyBroadcastOptionsSentOnExpiration() throws Exception {
+ optionsSentOnExpiration(false, null);
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 77612b9d8cef..ceacdb37d946 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -42,6 +42,7 @@ import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS
import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.UID_FIELD_NUMBER;
import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE;
import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
+import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT;
import static com.android.server.notification.PreferencesHelper.UNKNOWN_UID;
import static com.google.common.truth.Truth.assertThat;
@@ -3166,6 +3167,52 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
+ public void testTooManyGroups() {
+ for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) {
+ NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i),
+ String.valueOf(i));
+ mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
+ }
+ try {
+ NotificationChannelGroup group = new NotificationChannelGroup(
+ String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT),
+ String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT));
+ mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
+ fail("Allowed to create too many notification channel groups");
+ } catch (IllegalStateException e) {
+ // great
+ }
+ }
+
+ @Test
+ public void testTooManyGroups_xml() throws Exception {
+ String extraGroup = "EXTRA";
+ String extraGroup1 = "EXTRA1";
+
+ // create first... many... directly so we don't need a big xml blob in this test
+ for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) {
+ NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i),
+ String.valueOf(i));
+ mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
+ }
+
+ final String xml = "<ranking version=\"1\">\n"
+ + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
+ + "<channelGroup id=\"" + extraGroup + "\" name=\"hi\"/>"
+ + "<channelGroup id=\"" + extraGroup1 + "\" name=\"hi2\"/>"
+ + "</package>"
+ + "</ranking>";
+ TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
+ null);
+ parser.nextTag();
+ mHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+ assertNull(mHelper.getNotificationChannelGroup(extraGroup, PKG_O, UID_O));
+ assertNull(mHelper.getNotificationChannelGroup(extraGroup1, PKG_O, UID_O));
+ }
+
+ @Test
public void testRestoreMultiUser() throws Exception {
String pkg = "restore_pkg";
String channelId = "channelId";
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index f5e16a903a96..d6a5adb2eef7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1197,10 +1197,11 @@ public class RecentTasksTest extends WindowTestsBase {
@Test
public void testCreateRecentTaskInfo_detachedTask() {
final Task task = createTaskBuilder(".Task").build();
+ final ComponentName componentName = new ComponentName("com.foo", ".BarActivity");
new ActivityBuilder(mSupervisor.mService)
.setTask(task)
.setUid(NOBODY_UID)
- .setComponent(new ComponentName("com.foo", ".BarActivity"))
+ .setComponent(componentName)
.build();
final TaskDisplayArea tda = task.getDisplayArea();
@@ -1216,9 +1217,9 @@ public class RecentTasksTest extends WindowTestsBase {
info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
false /* getTasksAllowed */);
- assertTrue(info.topActivity == null);
- assertTrue(info.topActivityInfo == null);
- assertTrue(info.baseActivity == null);
+ assertFalse(info.topActivity.equals(componentName));
+ assertFalse(info.topActivityInfo.packageName.equals(componentName.getPackageName()));
+ assertFalse(info.baseActivity.equals(componentName));
// The task can be put in split screen even if it is not attached now.
task.removeImmediately();