Merge "SurfaceControl: Add setDropInputMode api" into rvc-dev
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6d4489e..c5d343d 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1275,27 +1275,18 @@
mContext.getUserId());
if (fd != null) {
FileOutputStream fos = null;
- final Bitmap tmp = BitmapFactory.decodeStream(resources.openRawResource(resid));
+ boolean ok = false;
try {
- // If the stream can't be decoded, treat it as an invalid input.
- if (tmp != null) {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- tmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
- // The 'close()' is the trigger for any server-side image manipulation,
- // so we must do that before waiting for completion.
- fos.close();
- completion.waitForCompletion();
- } else {
- throw new IllegalArgumentException(
- "Resource 0x" + Integer.toHexString(resid) + " is invalid");
- }
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ copyStreamToWallpaperFile(resources.openRawResource(resid), fos);
+ // The 'close()' is the trigger for any server-side image manipulation,
+ // so we must do that before waiting for completion.
+ fos.close();
+ completion.waitForCompletion();
} finally {
// Might be redundant but completion shouldn't wait unless the write
// succeeded; this is a fallback if it threw past the close+wait.
IoUtils.closeQuietly(fos);
- if (tmp != null) {
- tmp.recycle();
- }
}
}
} catch (RemoteException e) {
@@ -1537,22 +1528,13 @@
result, which, completion, mContext.getUserId());
if (fd != null) {
FileOutputStream fos = null;
- final Bitmap tmp = BitmapFactory.decodeStream(bitmapData);
try {
- // If the stream can't be decoded, treat it as an invalid input.
- if (tmp != null) {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- tmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
- fos.close();
- completion.waitForCompletion();
- } else {
- throw new IllegalArgumentException("InputStream is invalid");
- }
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ copyStreamToWallpaperFile(bitmapData, fos);
+ fos.close();
+ completion.waitForCompletion();
} finally {
IoUtils.closeQuietly(fos);
- if (tmp != null) {
- tmp.recycle();
- }
}
}
} catch (RemoteException e) {
diff --git a/core/java/android/debug/AdbManager.java b/core/java/android/debug/AdbManager.java
index 7714dd8..243f801 100644
--- a/core/java/android/debug/AdbManager.java
+++ b/core/java/android/debug/AdbManager.java
@@ -38,6 +38,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING)
public static final String WIRELESS_DEBUG_STATE_CHANGED_ACTION =
"com.android.server.adb.WIRELESS_DEBUG_STATUS";
@@ -46,6 +47,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING)
public static final String WIRELESS_DEBUG_PAIRED_DEVICES_ACTION =
"com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES";
@@ -59,6 +61,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING)
public static final String WIRELESS_DEBUG_PAIRING_RESULT_ACTION =
"com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT";
diff --git a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
index ce2d229..33209e1 100644
--- a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
+++ b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
@@ -16,6 +16,8 @@
package com.android.internal.app;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -27,6 +29,7 @@
import android.util.Log;
import android.view.View;
import android.widget.TextView;
+
import com.android.internal.R;
/**
@@ -48,6 +51,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
final Intent intent = getIntent();
mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3fd47b0..c00149d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5000,6 +5000,10 @@
<!-- Allows input events to be monitored. Very dangerous! @hide -->
<permission android:name="android.permission.MONITOR_INPUT"
android:protectionLevel="signature" />
+ <!-- Allows the use of FLAG_SLIPPERY, which permits touch events to slip from the current
+ window to the window where the touch currently is on top of. @hide -->
+ <permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES"
+ android:protectionLevel="signature" />
<!-- Allows the caller to change the associations between input devices and displays.
Very dangerous! @hide -->
<permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a7ef5e6..9aaf3fd 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -113,6 +113,7 @@
<uses-permission android:name="android.permission.SET_ORIENTATION" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.MONITOR_INPUT" />
+ <uses-permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES" />
<!-- DreamManager -->
<uses-permission android:name="android.permission.READ_DREAM_STATE" />
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index ec8bfc6..a32ab73 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -130,6 +130,12 @@
wrapper = null
bindService(false)
}
+
+ override fun onNullBinding(name: ComponentName?) {
+ if (DEBUG) Log.d(TAG, "onNullBinding $name")
+ wrapper = null
+ context.unbindService(this)
+ }
}
private fun handlePendingServiceMethods() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
index 2d3757c..12096bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
@@ -17,6 +17,9 @@
package com.android.systemui.controls.controller
import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
import android.os.UserHandle
import android.service.controls.IControlsActionCallback
import android.service.controls.IControlsProvider
@@ -43,6 +46,8 @@
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -57,8 +62,6 @@
private lateinit var subscriberService: IControlsSubscriber.Stub
@Mock
private lateinit var service: IControlsProvider.Stub
- @Mock
- private lateinit var loadCallback: ControlsBindingController.LoadCallback
@Captor
private lateinit var wrapperCaptor: ArgumentCaptor<ControlActionWrapper>
@@ -75,7 +78,7 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- mContext.addMockService(componentName, service)
+ context.addMockService(componentName, service)
executor = FakeExecutor(FakeSystemClock())
`when`(service.asBinder()).thenCallRealMethod()
`when`(service.queryLocalInterface(ArgumentMatchers.anyString())).thenReturn(service)
@@ -98,7 +101,36 @@
fun testBindService() {
manager.bindService()
executor.runAllReady()
- assertTrue(mContext.isBound(componentName))
+ assertTrue(context.isBound(componentName))
+ }
+
+ @Test
+ fun testNullBinding() {
+ val mockContext = mock(Context::class.java)
+ lateinit var serviceConnection: ServiceConnection
+ `when`(mockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer {
+ val component = (it.arguments[0] as Intent).component
+ if (component == componentName) {
+ serviceConnection = it.arguments[1] as ServiceConnection
+ serviceConnection.onNullBinding(component)
+ true
+ } else {
+ false
+ }
+ }
+
+ val nullManager = ControlsProviderLifecycleManager(
+ mockContext,
+ executor,
+ actionCallbackService,
+ UserHandle.of(0),
+ componentName
+ )
+
+ nullManager.bindService()
+ executor.runAllReady()
+
+ verify(mockContext).unbindService(serviceConnection)
}
@Test
@@ -109,7 +141,7 @@
manager.unbindService()
executor.runAllReady()
- assertFalse(mContext.isBound(componentName))
+ assertFalse(context.isBound(componentName))
}
@Test
@@ -119,7 +151,7 @@
verify(service).load(subscriberService)
- assertTrue(mContext.isBound(componentName))
+ assertTrue(context.isBound(componentName))
}
@Test
@@ -129,7 +161,7 @@
manager.unbindService()
executor.runAllReady()
- assertFalse(mContext.isBound(componentName))
+ assertFalse(context.isBound(componentName))
}
@Test
@@ -162,7 +194,7 @@
manager.maybeBindAndSubscribe(list, subscriberService)
executor.runAllReady()
- assertTrue(mContext.isBound(componentName))
+ assertTrue(context.isBound(componentName))
verify(service).subscribe(list, subscriberService)
}
@@ -173,7 +205,7 @@
manager.maybeBindAndSendAction(controlId, action)
executor.runAllReady()
- assertTrue(mContext.isBound(componentName))
+ assertTrue(context.isBound(componentName))
verify(service).action(eq(controlId), capture(wrapperCaptor),
eq(actionCallbackService))
assertEquals(action, wrapperCaptor.getValue().getWrappedAction())
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index ed83a64..95da946 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -18,6 +18,7 @@
import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull;
+import android.annotation.NonNull;
import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.Notification;
@@ -171,6 +172,12 @@
mAdbConnectionInfo = new AdbConnectionInfo();
}
+ static void sendBroadcastWithDebugPermission(@NonNull Context context, @NonNull Intent intent,
+ @NonNull UserHandle userHandle) {
+ context.sendBroadcastAsUser(intent, userHandle,
+ android.Manifest.permission.MANAGE_DEBUGGING);
+ }
+
class PairingThread extends Thread implements NsdManager.RegistrationListener {
private NsdManager mNsdManager;
private String mPublicKey;
@@ -1279,7 +1286,7 @@
? AdbManager.WIRELESS_STATUS_CONNECTED
: AdbManager.WIRELESS_STATUS_DISCONNECTED);
intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL);
}
private void onAdbdWifiServerConnected(int port) {
@@ -1351,7 +1358,8 @@
if (publicKey == null) {
Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION);
intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, AdbManager.WIRELESS_STATUS_FAIL);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent,
+ UserHandle.ALL);
} else {
Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION);
intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA,
@@ -1364,7 +1372,8 @@
}
PairDevice device = new PairDevice(fingerprints, hostname, false);
intent.putExtra(AdbManager.WIRELESS_PAIR_DEVICE_EXTRA, device);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent,
+ UserHandle.ALL);
// Add the key into the keystore
mAdbKeyStore.setLastConnectionTime(publicKey,
System.currentTimeMillis());
@@ -1378,14 +1387,14 @@
intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA,
AdbManager.WIRELESS_STATUS_CONNECTED);
intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL);
}
private void sendPairedDevicesToUI(Map<String, PairDevice> devices) {
Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION);
// Map is not serializable, so need to downcast
intent.putExtra(AdbManager.WIRELESS_DEVICES_EXTRA, (HashMap) devices);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL);
}
private void updateUIPairCode(String code) {
@@ -1395,7 +1404,7 @@
intent.putExtra(AdbManager.WIRELESS_PAIRING_CODE_EXTRA, code);
intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA,
AdbManager.WIRELESS_STATUS_PAIRING_CODE);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL);
}
}
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index 29bb542..5b16daa 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -431,7 +431,7 @@
? AdbManager.WIRELESS_STATUS_CONNECTED
: AdbManager.WIRELESS_STATUS_DISCONNECTED);
intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL);
Slog.i(TAG, "sent port broadcast port=" + port);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index b8de4a75..c82a45f 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -734,11 +734,8 @@
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
- if (!r.mAllowWhileInUsePermissionInFgs) {
- r.mAllowWhileInUsePermissionInFgs =
- shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
- callingUid, service, r, allowBackgroundActivityStarts);
- }
+ setFgsRestrictionLocked(callingPackage, callingPid, callingUid, r,
+ allowBackgroundActivityStarts);
return cmp;
}
@@ -1400,14 +1397,6 @@
+ String.format("0x%08X", manifestType)
+ " in service element of manifest file");
}
- // If the foreground service is not started from TOP process, do not allow it to
- // have while-in-use location/camera/microphone access.
- if (!r.mAllowWhileInUsePermissionInFgs) {
- Slog.w(TAG,
- "Foreground service started from background can not have "
- + "location/camera/microphone access: service "
- + r.shortInstanceName);
- }
}
boolean alreadyStartedOp = false;
boolean stopProcStatsOp = false;
@@ -1455,6 +1444,56 @@
ignoreForeground = true;
}
+ if (!ignoreForeground) {
+ if (r.mStartForegroundCount == 0) {
+ /*
+ If the service was started with startService(), not
+ startForegroundService(), and if startForeground() isn't called within
+ mFgsStartForegroundTimeoutMs, then we check the state of the app
+ (who owns the service, which is the app that called startForeground())
+ again. If the app is in the foreground, or in any other cases where
+ FGS-starts are allowed, then we still allow the FGS to be started.
+ Otherwise, startForeground() would fail.
+
+ If the service was started with startForegroundService(), then the service
+ must call startForeground() within a timeout anyway, so we don't need this
+ check.
+ */
+ if (!r.fgRequired) {
+ final long delayMs = SystemClock.elapsedRealtime() - r.createRealTime;
+ if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
+ resetFgsRestrictionLocked(r);
+ setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.pid,
+ r.appInfo.uid, r, false);
+ EventLog.writeEvent(0x534e4554, "183147114",
+ r.appInfo.uid,
+ "call setFgsRestrictionLocked again due to "
+ + "startForegroundTimeout");
+ }
+ }
+ } else if (r.mStartForegroundCount >= 1) {
+ // The second or later time startForeground() is called after service is
+ // started. Check for app state again.
+ final long delayMs = SystemClock.elapsedRealtime() -
+ r.mLastSetFgsRestrictionTime;
+ if (delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs) {
+ setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.pid,
+ r.appInfo.uid, r, false);
+ EventLog.writeEvent(0x534e4554, "183147114", r.appInfo.uid,
+ "call setFgsRestrictionLocked for "
+ + (r.mStartForegroundCount + 1) + "th startForeground");
+ }
+ }
+ // If the foreground service is not started from TOP process, do not allow it to
+ // have while-in-use location/camera/microphone access.
+ if (!r.mAllowWhileInUsePermissionInFgs) {
+ Slog.w(TAG,
+ "Foreground service started from background can not have "
+ + "location/camera/microphone access: service "
+ + r.shortInstanceName);
+ }
+ }
+
// Apps under strict background restrictions simply don't get to have foreground
// services, so now that we've enforced the startForegroundService() contract
// we only do the machinery of making the service foreground when the app
@@ -1490,6 +1529,7 @@
active.mNumActive++;
}
r.isForeground = true;
+ r.mStartForegroundCount++;
if (!stopProcStatsOp) {
ServiceState stracker = r.getTracker();
if (stracker != null) {
@@ -1548,6 +1588,7 @@
decActiveForegroundAppLocked(smap, r);
}
r.isForeground = false;
+ resetFgsRestrictionLocked(r);
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -2107,12 +2148,7 @@
}
}
- if (!s.mAllowWhileInUsePermissionInFgs) {
- s.mAllowWhileInUsePermissionInFgs =
- shouldAllowWhileInUsePermissionInFgsLocked(callingPackage,
- callingPid, callingUid,
- service, s, false);
- }
+ setFgsRestrictionLocked(callingPackage, callingPid, callingUid, s, false);
if (s.app != null) {
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
@@ -3408,7 +3444,7 @@
r.isForeground = false;
r.foregroundId = 0;
r.foregroundNoti = null;
- r.mAllowWhileInUsePermissionInFgs = false;
+ resetFgsRestrictionLocked(r);
// Clear start entries.
r.clearDeliveredStartsLocked();
@@ -4889,7 +4925,7 @@
* @return true if allow, false otherwise.
*/
private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage,
- int callingPid, int callingUid, Intent intent, ServiceRecord r,
+ int callingPid, int callingUid, ServiceRecord r,
boolean allowBackgroundActivityStarts) {
// Is the background FGS start restriction turned on?
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
@@ -4960,4 +4996,33 @@
}
return false;
}
+
+ boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
+ String callingPackage) {
+ return shouldAllowWhileInUsePermissionInFgsLocked(
+ callingPackage, callingPid, callingUid, null, false);
+ }
+
+ /**
+ * In R, mAllowWhileInUsePermissionInFgs is to allow while-in-use permissions in foreground
+ * service or not. while-in-use permissions in FGS started from background might be restricted.
+ * @param callingPackage caller app's package name.
+ * @param callingUid caller app's uid.
+ * @param r the service to start.
+ * @return true if allow, false otherwise.
+ */
+ private void setFgsRestrictionLocked(String callingPackage,
+ int callingPid, int callingUid, ServiceRecord r,
+ boolean allowBackgroundActivityStarts) {
+ r.mLastSetFgsRestrictionTime = SystemClock.elapsedRealtime();
+ if (!r.mAllowWhileInUsePermissionInFgs) {
+ r.mAllowWhileInUsePermissionInFgs = shouldAllowWhileInUsePermissionInFgsLocked(
+ callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
+ }
+ }
+
+ private void resetFgsRestrictionLocked(ServiceRecord r) {
+ r.mAllowWhileInUsePermissionInFgs = false;
+ r.mLastSetFgsRestrictionTime = 0;
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 135ac9a..cc1bda7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -87,6 +87,7 @@
static final String KEY_PROCESS_START_ASYNC = "process_start_async";
static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
+ static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
@@ -120,6 +121,7 @@
private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
+ private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
// Flag stored in the DeviceConfig API.
@@ -272,6 +274,12 @@
// this long.
public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
+ /**
+ * When service started from background, before the timeout it can be promoted to FGS by calling
+ * Service.startForeground().
+ */
+ volatile long mFgsStartForegroundTimeoutMs = DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS;
+
// Indicates whether the activity starts logging is enabled.
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -415,6 +423,9 @@
case KEY_MIN_ASSOC_LOG_DURATION:
updateMinAssocLogDuration();
break;
+ case KEY_FGS_START_FOREGROUND_TIMEOUT:
+ updateFgsStartForegroundTimeout();
+ break;
default:
break;
}
@@ -687,6 +698,13 @@
/* defaultValue */ DEFAULT_MIN_ASSOC_LOG_DURATION);
}
+ private void updateFgsStartForegroundTimeout() {
+ mFgsStartForegroundTimeoutMs = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_FGS_START_FOREGROUND_TIMEOUT,
+ DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS);
+ }
+
void dump(PrintWriter pw) {
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":");
@@ -759,6 +777,8 @@
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.toArray()));
pw.print(" "); pw.print(KEY_MIN_ASSOC_LOG_DURATION); pw.print("=");
pw.println(MIN_ASSOC_LOG_DURATION);
+ pw.print(" "); pw.print(KEY_FGS_START_FOREGROUND_TIMEOUT); pw.print("=");
+ pw.println(mFgsStartForegroundTimeoutMs);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 9c96e6e..5583c51 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -138,6 +138,10 @@
// allow while-in-use permissions in foreground service or not.
// while-in-use permissions in FGS started from background might be restricted.
boolean mAllowWhileInUsePermissionInFgs;
+ // The number of times Service.startForeground() is called;
+ int mStartForegroundCount;
+ // Last time mAllowWhileInUsePermissionInFgs is set.
+ long mLastSetFgsRestrictionTime;
// the most recent package that start/bind this service.
String mRecentCallingPackage;
@@ -400,6 +404,8 @@
}
pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
pw.println(mAllowWhileInUsePermissionInFgs);
+ pw.print(prefix); pw.print("startForegroundCount=");
+ pw.println(mStartForegroundCount);
pw.print(prefix); pw.print("recentCallingPackage=");
pw.println(mRecentCallingPackage);
if (delayed) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6b43d99..0833d26 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2470,7 +2470,7 @@
}
}
- private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
+ void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
boolean fromApp, boolean fromListener) {
Objects.requireNonNull(group);
Objects.requireNonNull(pkg);
@@ -3488,7 +3488,8 @@
final int callingUid = Binder.getCallingUid();
NotificationChannelGroup groupToDelete =
- mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
+ mPreferencesHelper.getNotificationChannelGroupWithChannels(
+ pkg, callingUid, groupId, false);
if (groupToDelete != null) {
// Preflight for allowability
final int userId = UserHandle.getUserId(callingUid);
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index bc78d66..fba4f1a 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -759,6 +759,9 @@
if (r == null) {
throw new IllegalArgumentException("Invalid package");
}
+ if (fromTargetApp) {
+ group.setBlocked(false);
+ }
final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
if (oldGroup != null) {
group.setChannels(oldGroup.getChannels());
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index e6a75ab..0b2b06d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -345,7 +345,11 @@
if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) {
// Aggressively close old sessions because we are running low on storage
// Their staging dirs will be removed too
- session.abandon();
+ PackageInstallerSession root = !session.hasParentSessionId()
+ ? session : mSessions.get(session.getParentSessionId());
+ if (!root.isDestroyed()) {
+ root.abandon();
+ }
} else {
// Session is new enough, so it deserves to be kept even on low storage
unclaimedStagingDirsOnVolume.remove(session.stageDir);
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 5e04171..354f5b9 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -409,6 +409,8 @@
}
if (bp.perm != null && Objects.equals(bp.perm.getPackageName(), p.getPackageName())
&& Objects.equals(bp.perm.getName(), p.getName())) {
+ bp.perm.setFlags(bp.perm.getFlags() & ~PermissionInfo.FLAG_INSTALLED);
+ bp.perm = p.setFlags(p.getFlags() | PermissionInfo.FLAG_INSTALLED);
bp.protectionLevel = p.getProtectionLevel();
}
if (bp.isRuntime() && (ownerChanged || wasNonRuntime)) {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index cc6a0a4..05875d9 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -62,7 +62,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -835,20 +834,6 @@
}
/**
- * Only trusted overlays are allowed to use FLAG_SLIPPERY.
- */
- static int sanitizeFlagSlippery(int flags, int privateFlags, String name) {
- if ((flags & FLAG_SLIPPERY) == 0) {
- return flags;
- }
- if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
- return flags;
- }
- Slog.w(TAG, "Removing FLAG_SLIPPERY for non-trusted overlay " + name);
- return flags & ~FLAG_SLIPPERY;
- }
-
- /**
* Sanitize the layout parameters coming from a client. Allows the policy
* to do things like ensure that windows of a specific type can't take
* input focus.
@@ -931,7 +916,6 @@
}
break;
}
- attrs.flags = sanitizeFlagSlippery(attrs.flags, attrs.privateFlags, win.getName());
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1da398aef..aa598d0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1566,6 +1566,7 @@
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
displayPolicy.adjustWindowParamsLw(win, win.mAttrs, callingPid, callingUid);
+ attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), callingUid, callingPid);
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
if (res != WindowManagerGlobal.ADD_OKAY) {
@@ -2150,6 +2151,7 @@
if (attrs != null) {
displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
win.mToken.adjustWindowParams(win, attrs);
+ attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), uid, pid);
// if they don't have the permission, mask out the status bar bits
if (seq == win.mSeq) {
int systemUiVisibility = attrs.systemUiVisibility
@@ -8050,6 +8052,23 @@
}
/**
+ * You need ALLOW_SLIPPERY_TOUCHES permission to be able to set FLAG_SLIPPERY.
+ */
+ private int sanitizeFlagSlippery(int flags, String windowName, int callingUid, int callingPid) {
+ if ((flags & FLAG_SLIPPERY) == 0) {
+ return flags;
+ }
+ final int permissionResult = mContext.checkPermission(
+ android.Manifest.permission.ALLOW_SLIPPERY_TOUCHES, callingPid, callingUid);
+ if (permissionResult != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Removing FLAG_SLIPPERY from '" + windowName
+ + "' because it doesn't have ALLOW_SLIPPERY_TOUCHES permission");
+ return flags & ~FLAG_SLIPPERY;
+ }
+ return flags;
+ }
+
+ /**
* Assigns an InputChannel to a SurfaceControl and configures it to receive
* touch input according to it's on-screen geometry.
*
@@ -8087,7 +8106,7 @@
h.token = channelToken;
h.name = name;
- flags = DisplayPolicy.sanitizeFlagSlippery(flags, privateFlags, name);
+ flags = sanitizeFlagSlippery(flags, name, callingUid, callingPid);
final int sanitizedFlags = flags & (LayoutParams.FLAG_NOT_TOUCHABLE | FLAG_SLIPPERY);
h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 13ea6ba..a7452e8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -9381,6 +9381,9 @@
final ComponentName doComponent = mOwners.getDeviceOwnerComponent();
final ComponentName poComponent =
mOwners.getProfileOwnerComponent(userHandle.getIdentifier());
+ if (supervisorComponent == null) {
+ return null;
+ }
if (supervisorComponent.equals(doComponent) || supervisorComponent.equals(
poComponent)) {
return supervisorComponent;
diff --git a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
index cffff66..02cf971 100644
--- a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
@@ -23,7 +23,14 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.debug.AdbManager;
+import android.debug.IAdbManager;
+import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Log;
@@ -105,6 +112,7 @@
public void tearDown() throws Exception {
mKeyStore.deleteKeyStore();
setAllowedConnectionTime(mOriginalAllowedConnectionTime);
+ dropShellPermissionIdentity();
}
/**
@@ -813,6 +821,108 @@
return hasAtLeastOneLetter;
}
+ CountDownLatch mAdbActionLatch = new CountDownLatch(1);
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.i(TAG, "Received intent action=" + action);
+ if (AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION.equals(action)) {
+ assertEquals("Received broadcast without MANAGE_DEBUGGING permission.",
+ context.checkSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING),
+ PackageManager.PERMISSION_GRANTED);
+ Log.i(TAG, "action=" + action + " paired_device=" + intent.getSerializableExtra(
+ AdbManager.WIRELESS_DEVICES_EXTRA).toString());
+ mAdbActionLatch.countDown();
+ } else if (AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION.equals(action)) {
+ assertEquals("Received broadcast without MANAGE_DEBUGGING permission.",
+ context.checkSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING),
+ PackageManager.PERMISSION_GRANTED);
+ int status = intent.getIntExtra(AdbManager.WIRELESS_STATUS_EXTRA,
+ AdbManager.WIRELESS_STATUS_DISCONNECTED);
+ Log.i(TAG, "action=" + action + " status=" + status);
+ mAdbActionLatch.countDown();
+ } else if (AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION.equals(action)) {
+ assertEquals("Received broadcast without MANAGE_DEBUGGING permission.",
+ context.checkSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING),
+ PackageManager.PERMISSION_GRANTED);
+ Integer res = intent.getIntExtra(
+ AdbManager.WIRELESS_STATUS_EXTRA,
+ AdbManager.WIRELESS_STATUS_FAIL);
+ Log.i(TAG, "action=" + action + " result=" + res);
+
+ if (res.equals(AdbManager.WIRELESS_STATUS_PAIRING_CODE)) {
+ String pairingCode = intent.getStringExtra(
+ AdbManager.WIRELESS_PAIRING_CODE_EXTRA);
+ Log.i(TAG, "pairingCode=" + pairingCode);
+ } else if (res.equals(AdbManager.WIRELESS_STATUS_CONNECTED)) {
+ int port = intent.getIntExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, 0);
+ Log.i(TAG, "port=" + port);
+ }
+ mAdbActionLatch.countDown();
+ }
+ }
+ };
+
+ private void adoptShellPermissionIdentity() {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(android.Manifest.permission.MANAGE_DEBUGGING);
+ }
+
+ private void dropShellPermissionIdentity() {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+ @Test
+ public void testBroadcastReceiverWithPermissions() throws Exception {
+ adoptShellPermissionIdentity();
+ final IAdbManager mAdbManager = IAdbManager.Stub.asInterface(
+ ServiceManager.getService(Context.ADB_SERVICE));
+ IntentFilter intentFilter =
+ new IntentFilter(AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION);
+ intentFilter.addAction(AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION);
+ intentFilter.addAction(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION);
+ assertEquals("Context does not have MANAGE_DEBUGGING permission.",
+ mContext.checkSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING),
+ PackageManager.PERMISSION_GRANTED);
+ try {
+ mContext.registerReceiver(mReceiver, intentFilter);
+ mAdbManager.enablePairingByPairingCode();
+ if (!mAdbActionLatch.await(TIMEOUT, TIMEOUT_TIME_UNIT)) {
+ fail("Receiver did not receive adb intent action within the timeout duration");
+ }
+ } finally {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ }
+
+ @Test
+ public void testBroadcastReceiverWithoutPermissions() throws Exception {
+ adoptShellPermissionIdentity();
+ final IAdbManager mAdbManager = IAdbManager.Stub.asInterface(
+ ServiceManager.getService(Context.ADB_SERVICE));
+ IntentFilter intentFilter =
+ new IntentFilter(AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION);
+ intentFilter.addAction(AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION);
+ intentFilter.addAction(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION);
+ mAdbManager.enablePairingByPairingCode();
+
+ dropShellPermissionIdentity();
+ assertEquals("Context has MANAGE_DEBUGGING permission.",
+ mContext.checkSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING),
+ PackageManager.PERMISSION_DENIED);
+ try {
+ mContext.registerReceiver(mReceiver, intentFilter);
+
+ if (mAdbActionLatch.await(TIMEOUT, TIMEOUT_TIME_UNIT)) {
+ fail("Broadcast receiver received adb action intent without debug permissions");
+ }
+ } finally {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ }
+
/**
* Runs an adb test with the provided configuration.
*
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
old mode 100755
new mode 100644
index 67b7a79..9394eb8
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -178,6 +178,8 @@
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
+import com.google.common.collect.ImmutableList;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -201,6 +203,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
@@ -244,6 +247,8 @@
@Mock
Resources mResources;
@Mock
+ ActivityManagerInternal mAmi;
+ @Mock
RankingHandler mRankingHandler;
private static final int MAX_POST_DELAY = 1000;
@@ -415,7 +420,6 @@
DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class);
when(deviceIdleInternal.getNotificationWhitelistDuration()).thenReturn(3000L);
- ActivityManagerInternal activityManagerInternal = mock(ActivityManagerInternal.class);
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
@@ -426,7 +430,7 @@
LocalServices.removeServiceForTest(DeviceIdleInternal.class);
LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
- LocalServices.addService(ActivityManagerInternal.class, activityManagerInternal);
+ LocalServices.addService(ActivityManagerInternal.class, mAmi);
mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
@@ -503,7 +507,7 @@
mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
mAppOpsManager, mUm, mHistoryManager, mStatsManager,
mock(TelephonyManager.class),
- mock(ActivityManagerInternal.class));
+ mAmi);
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
mService.setAudioManager(mAudioManager);
@@ -2450,7 +2454,8 @@
.thenReturn(associations);
NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c");
mService.setPreferencesHelper(mPreferencesHelper);
- when(mPreferencesHelper.getNotificationChannelGroup(eq(ncg.getId()), eq(PKG), anyInt()))
+ when(mPreferencesHelper.getNotificationChannelGroupWithChannels(
+ eq(PKG), anyInt(), eq(ncg.getId()), anyBoolean()))
.thenReturn(ncg);
reset(mListeners);
mBinderService.deleteNotificationChannelGroup(PKG, ncg.getId());
@@ -2460,6 +2465,56 @@
}
@Test
+ public void testDeleteChannelGroupChecksForFgses() throws Exception {
+ List<String> associations = new ArrayList<>();
+ associations.add("a");
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
+ CountDownLatch latch = new CountDownLatch(2);
+ mService.createNotificationChannelGroup(
+ PKG, mUid, new NotificationChannelGroup("group", "group"), true, false);
+ new Thread(() -> {
+ NotificationChannel notificationChannel = new NotificationChannel("id", "id",
+ NotificationManager.IMPORTANCE_HIGH);
+ notificationChannel.setGroup("group");
+ ParceledListSlice<NotificationChannel> pls =
+ new ParceledListSlice(ImmutableList.of(notificationChannel));
+ try {
+ mBinderService.createNotificationChannelsForPackage(PKG, mUid, pls);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ latch.countDown();
+ }).start();
+ new Thread(() -> {
+ try {
+ synchronized (this) {
+ wait(5000);
+ }
+ mService.createNotificationChannelGroup(PKG, mUid,
+ new NotificationChannelGroup("new", "new group"), true, false);
+ NotificationChannel notificationChannel =
+ new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH);
+ notificationChannel.setGroup("new");
+ ParceledListSlice<NotificationChannel> pls =
+ new ParceledListSlice(ImmutableList.of(notificationChannel));
+ try {
+ mBinderService.createNotificationChannelsForPackage(PKG, mUid, pls);
+ mBinderService.deleteNotificationChannelGroup(PKG, "group");
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ latch.countDown();
+ }).start();
+
+ latch.await();
+ verify(mAmi).hasForegroundServiceNotification(anyString(), anyInt(), anyString());
+ }
+
+ @Test
public void testUpdateNotificationChannelFromPrivilegedListener_success() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
List<String> associations = new ArrayList<>();
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 2e49929..439f059 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2132,6 +2132,19 @@
}
@Test
+ public void testIsGroupBlocked_appCannotCreateAsBlocked() throws Exception {
+ NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
+ group.setBlocked(true);
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
+ assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
+
+ NotificationChannelGroup group3 = group.clone();
+ group3.setBlocked(false);
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true);
+ assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
+ }
+
+ @Test
public void testIsGroup_appCannotResetBlock() throws Exception {
NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
@@ -3270,7 +3283,7 @@
public void testGetConversations_noDisabledGroups() {
NotificationChannelGroup group = new NotificationChannelGroup("a", "a");
group.setBlocked(true);
- mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
+ mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, false);
NotificationChannel parent = new NotificationChannel("parent", "p", 1);
mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);