diff options
7 files changed, 127 insertions, 24 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index c2599666e60d..8c0cf510b009 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2030,7 +2030,7 @@ public class NotificationManagerService extends SystemService { } } - private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group, + void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group, boolean fromApp, boolean fromListener) { Preconditions.checkNotNull(group); Preconditions.checkNotNull(pkg); @@ -2795,7 +2795,8 @@ public class NotificationManagerService extends SystemService { 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/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index a096f2252680..7c1ac2737469 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -330,7 +330,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements 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.isStaged() || (root.isStaged() && root.isStagedSessionReady()))) + { + root.abandon(); + } } else { // Session is new enough, so it deserves to be kept even on low storage unclaimedStagingDirsOnVolume.remove(session.stageDir); @@ -653,7 +659,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this, mInstallThread.getLooper(), mStagingManager, sessionId, userId, installerPackageName, callingUid, params, createdMillis, stageDir, stageCid, false, - false, false, null, SessionInfo.INVALID_ID, false, false, false, + false, false, false, null, SessionInfo.INVALID_ID, false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, ""); synchronized (mSessions) { @@ -803,7 +809,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements synchronized (mSessions) { final PackageInstallerSession session = mSessions.get(sessionId); - return session != null + return (session != null && !(session.isStaged() && session.isDestroyed())) ? session.generateInfoForCaller(true /*withIcon*/, Binder.getCallingUid()) : null; } @@ -824,7 +830,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements synchronized (mSessions) { for (int i = 0; i < mSessions.size(); i++) { final PackageInstallerSession session = mSessions.valueAt(i); - if (session.userId == userId && !session.hasParentSessionId()) { + if (session.userId == userId && !session.hasParentSessionId() + && !(session.isStaged() && session.isDestroyed())) { result.add(session.generateInfoForCaller(false, callingUid)); } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index d40eae5bad09..f5fc13acf6f0 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -151,6 +151,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid"; private static final String ATTR_PREPARED = "prepared"; private static final String ATTR_COMMITTED = "committed"; + private static final String ATTR_DESTROYED = "destroyed"; private static final String ATTR_SEALED = "sealed"; private static final String ATTR_MULTI_PACKAGE = "multiPackage"; private static final String ATTR_PARENT_SESSION_ID = "parentSessionId"; @@ -413,8 +414,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager, int sessionId, int userId, String installerPackageName, int installerUid, SessionParams params, long createdMillis, - File stageDir, String stageCid, boolean prepared, boolean committed, boolean sealed, - @Nullable int[] childSessionIds, int parentSessionId, boolean isReady, + File stageDir, String stageCid, boolean prepared, boolean committed, boolean destroyed, + boolean sealed, @Nullable int[] childSessionIds, int parentSessionId, boolean isReady, boolean isFailed, boolean isApplied, int stagedSessionErrorCode, String stagedSessionErrorMessage) { mCallback = callback; @@ -449,6 +450,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mPrepared = prepared; mCommitted = committed; + mDestroyed = destroyed; mStagedSessionReady = isReady; mStagedSessionFailed = isFailed; mStagedSessionApplied = isApplied; @@ -559,6 +561,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** {@hide} */ + boolean isDestroyed() { + synchronized (mLock) { + return mDestroyed; + } + } + /** Returns true if a staged session has reached a final state and can be forgotten about */ public boolean isStagedAndInTerminalState() { synchronized (mLock) { @@ -2421,7 +2430,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { */ void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException { synchronized (mLock) { - if (mDestroyed) { + if (mDestroyed && !params.isStaged) { return; } @@ -2443,6 +2452,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } writeBooleanAttribute(out, ATTR_PREPARED, isPrepared()); writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted()); + writeBooleanAttribute(out, ATTR_DESTROYED, isDestroyed()); writeBooleanAttribute(out, ATTR_SEALED, isSealed()); writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage); @@ -2544,6 +2554,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID); final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true); final boolean committed = readBooleanAttribute(in, ATTR_COMMITTED); + final boolean destroyed = readBooleanAttribute(in, ATTR_DESTROYED); final boolean sealed = readBooleanAttribute(in, ATTR_SEALED); final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID, SessionInfo.INVALID_ID); @@ -2631,8 +2642,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return new PackageInstallerSession(callback, context, pm, sessionProvider, installerThread, stagingManager, sessionId, userId, installerPackageName, installerUid, params, createdMillis, stageDir, stageCid, prepared, committed, - sealed, childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied, - stagedSessionErrorCode, stagedSessionErrorMessage); + destroyed, sealed, childSessionIdsArray, parentSessionId, isReady, isFailed, + isApplied, stagedSessionErrorCode, stagedSessionErrorMessage); } /** diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index b6de39538f1b..e620da54c872 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -99,6 +99,9 @@ public class StagingManager { synchronized (mStagedSessions) { for (int i = 0; i < mStagedSessions.size(); i++) { final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i); + if (stagedSession.isDestroyed()) { + continue; + } result.add(stagedSession.generateInfoForCaller(false /*icon*/, callingUid)); } } diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index 3fd4e83b9494..361f66e3106a 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -110,6 +110,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Debug; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -204,6 +205,11 @@ class TaskRecord extends ConfigurationContainer { static final int REPARENT_LEAVE_STACK_IN_PLACE = 2; /** + * Used to identify if the activity that is installed from device's system image. + */ + boolean mIsEffectivelySystemApp; + + /** * The factory used to create {@link TaskRecord}. This allows OEM subclass {@link TaskRecord}. */ private static TaskRecordFactory sTaskRecordFactory; @@ -869,17 +875,25 @@ class TaskRecord extends ConfigurationContainer { /** Sets the original intent, and the calling uid and package. */ void setIntent(ActivityRecord r) { - mCallingUid = r.launchedFromUid; - mCallingPackage = r.launchedFromPackage; - setIntent(r.intent, r.info); + boolean updateIdentity = false; + if (this.intent == null) { + updateIdentity = true; + } else if (!mNeverRelinquishIdentity) { + updateIdentity = (effectiveUid == Process.SYSTEM_UID || mIsEffectivelySystemApp + || effectiveUid == r.info.applicationInfo.uid); + } + if (updateIdentity) { + mCallingUid = r.launchedFromUid; + mCallingPackage = r.launchedFromPackage; + setIntent(r.intent, r.info); + } setLockTaskAuth(r); } /** Sets the original intent, _without_ updating the calling uid or package. */ private void setIntent(Intent _intent, ActivityInfo info) { if (intent == null) { - mNeverRelinquishIdentity = - (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; + mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; } else if (mNeverRelinquishIdentity) { return; } @@ -892,6 +906,7 @@ class TaskRecord extends ConfigurationContainer { rootAffinity = affinity; } effectiveUid = info.applicationInfo.uid; + mIsEffectivelySystemApp = info.applicationInfo.isSystemApp(); stringName = null; if (info.targetActivity == null) { @@ -1662,12 +1677,12 @@ class TaskRecord extends ConfigurationContainer { // utility activities. int activityNdx; final int numActivities = mActivities.size(); - final boolean relinquish = numActivities != 0 && - (mActivities.get(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0; - for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; - ++activityNdx) { + for (activityNdx = 0; activityNdx < numActivities; ++activityNdx) { final ActivityRecord r = mActivities.get(activityNdx); - if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) { + if ((r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0 + || (r.info.applicationInfo.uid != Process.SYSTEM_UID + && !r.info.applicationInfo.isSystemApp() + && r.info.applicationInfo.uid != effectiveUid)) { // This will be the top activity for determining taskDescription. Pre-inc to // overcome initial decrement below. ++activityNdx; @@ -1739,15 +1754,27 @@ class TaskRecord extends ConfigurationContainer { int findEffectiveRootIndex() { int effectiveNdx = 0; final int topActivityNdx = mActivities.size() - 1; + ActivityRecord root = null; for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) { final ActivityRecord r = mActivities.get(activityNdx); if (r.finishing) { continue; } - effectiveNdx = activityNdx; - if ((r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) { + + if (root == null) { + // Set this as the candidate root since it isn't finishing. + root = r; + effectiveNdx = activityNdx; + } + final int uid = root == r ? effectiveUid : r.info.applicationInfo.uid; + if ((root.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0 + || (root.info.applicationInfo.uid != Process.SYSTEM_UID + && !root.info.applicationInfo.isSystemApp() + && root.info.applicationInfo.uid != uid)) { break; } + effectiveNdx = activityNdx; + root = r; } return effectiveNdx; } diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java index d3f33a152734..3dd56bc48aa1 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java @@ -168,6 +168,7 @@ public class PackageInstallerSessionTest { /* stageCid */ null, /* prepared */ true, /* committed */ true, + /* destroyed */ staged ? true : false, /* sealed */ false, // Setting to true would trigger some PM logic. /* childSessionIds */ childSessionIds != null ? childSessionIds : new int[0], /* parentSessionId */ parentSessionId, diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 6cd0a2aeaac1..90a680b6c43b 100755..100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -151,6 +151,8 @@ import com.android.server.pm.PackageManagerService; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wm.WindowManagerInternal; +import com.google.common.collect.ImmutableList; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -170,6 +172,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; @SmallTest @@ -1930,7 +1933,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mCompanionMgr.getAssociations(PKG, mUid)).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()); @@ -1940,6 +1944,55 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testDeleteChannelGroupChecksForFgses() throws Exception { + List<String> associations = new ArrayList<>(); + associations.add("a"); + when(mCompanionMgr.getAssociations(PKG, 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<>(); |