Merge "Visit URIs in landscape/portrait custom remote views." into rvc-dev
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 21c9399..7309843 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2510,6 +2510,17 @@
if (person != null && person.getIconUri() != null) {
visitor.accept(person.getIconUri());
}
+
+ final RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
+ extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+ if (history != null) {
+ for (int i = 0; i < history.length; i++) {
+ RemoteInputHistoryItem item = history[i];
+ if (item.getUri() != null) {
+ visitor.accept(item.getUri());
+ }
+ }
+ }
}
if (MessagingStyle.class.equals(getNotificationStyle()) && extras != null) {
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 1b3c46f..bf1219c 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -261,6 +261,12 @@
*/
public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
+ /**
+ * The maximum length of Shortcut ID. IDs will be truncated at this limit.
+ * @hide
+ */
+ public static final int MAX_ID_LENGTH = 1000;
+
/** @hide */
@IntDef(prefix = { "DISABLED_REASON_" }, value = {
DISABLED_REASON_NOT_DISABLED,
@@ -436,8 +442,7 @@
private ShortcutInfo(Builder b) {
mUserId = b.mContext.getUserId();
-
- mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
+ mId = getSafeId(Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided"));
// Note we can't do other null checks here because SM.updateShortcuts() takes partial
// information.
@@ -539,6 +544,14 @@
return ret;
}
+ @NonNull
+ private static String getSafeId(@NonNull String id) {
+ if (id.length() > MAX_ID_LENGTH) {
+ return id.substring(0, MAX_ID_LENGTH);
+ }
+ return id;
+ }
+
/**
* Throws if any of the mandatory fields is not set.
*
@@ -2090,7 +2103,8 @@
final ClassLoader cl = getClass().getClassLoader();
mUserId = source.readInt();
- mId = source.readString8();
+ mId = getSafeId(Preconditions.checkStringNotEmpty(source.readString8(),
+ "Shortcut ID must be provided"));
mPackageName = source.readString8();
mActivity = source.readParcelable(cl);
mFlags = source.readInt();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 64fd392..29ccca6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -162,6 +162,7 @@
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
import android.app.ApplicationThreadConstants;
+import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.ContentProviderHolder;
import android.app.IActivityController;
@@ -363,6 +364,7 @@
import com.android.server.firewall.IntentFirewall;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.pm.Installer;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.uri.GrantUri;
import com.android.server.uri.NeededUriGrants;
@@ -8336,7 +8338,54 @@
Binder token = new Binder();
sCallerIdentity.set(new Identity(
token, Binder.getCallingPid(), Binder.getCallingUid()));
+ boolean handlingSecurityViolation = false;
try {
+ // This method is exposed to the VNDK and to avoid changing its
+ // signature we just use the first package in the UID. For shared
+ // UIDs we may blame the wrong app but that is Okay as they are
+ // in the same security/privacy sandbox.
+ final int uid = Binder.getCallingUid();
+ // Here we handle some of the special UIDs (mediaserver, systemserver, etc)
+ // Note: This is moved to AppOpsManager.resolvePackageName in future versions.
+ final String packageName;
+ if (uid == Process.ROOT_UID) {
+ packageName = "root";
+ } else if (uid == Process.SHELL_UID) {
+ packageName = "com.android.shell";
+ } else if (uid == Process.MEDIA_UID) {
+ packageName = "media";
+ } else if (uid == Process.AUDIOSERVER_UID) {
+ packageName = "audioserver";
+ } else if (uid == Process.CAMERASERVER_UID) {
+ packageName = "cameraserver";
+ } else if (uid == Process.SYSTEM_UID) {
+ packageName = "android";
+ } else {
+ packageName = null;
+ }
+
+ final AndroidPackage androidPackage;
+ if (packageName != null) {
+ androidPackage = mPackageManagerInt.getPackage(packageName);
+ } else {
+ androidPackage = mPackageManagerInt.getPackage(uid);
+ }
+ if (androidPackage == null) {
+ Log.e(TAG, "Cannot find package for uid: " + uid);
+ handlingSecurityViolation = true;
+ return null;
+ }
+
+ final ApplicationInfo appInfo = mPackageManagerInt.getApplicationInfo(
+ androidPackage.getPackageName(), /*flags*/0, Process.SYSTEM_UID,
+ UserHandle.USER_SYSTEM);
+ if (!appInfo.isVendor() && !appInfo.isSystemApp() && !appInfo.isSystemExt()
+ && !appInfo.isProduct()) {
+ Log.e(TAG, "openContentUri may only be used by vendor/system/product.");
+ handlingSecurityViolation = true;
+ return null;
+ }
+
pfd = cph.provider.openFile(null, null, uri, "r", null, token);
} catch (FileNotFoundException e) {
// do nothing; pfd will be returned null
@@ -8344,7 +8393,16 @@
// Ensure that whatever happens, we clean up the identity state
sCallerIdentity.remove();
// Ensure we're done with the provider.
- removeContentProviderExternalUnchecked(name, null, userId);
+ try {
+ removeContentProviderExternalUnchecked(name, null, userId);
+ } catch (SecurityException e) {
+ // A SecurityException may be thrown from computeOomAdjLocked if the calling
+ // UID is that of a malicious app accessing this hidden API. In that case
+ // we're already handling that by returning null, so tolerate this.
+ if (!handlingSecurityViolation) {
+ throw e;
+ }
+ }
}
} else {
Slog.d(TAG, "Failed to get provider for authority '" + name + "'");
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index ab63285..4eba871 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -90,7 +90,7 @@
private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
@VisibleForTesting
- static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 5000;
+ static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 50000;
@VisibleForTesting
static final int NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT = 6000;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index ca77049..088d693 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -53,6 +53,7 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
+import java.util.Collections;
import java.util.Locale;
/**
@@ -223,6 +224,15 @@
});
}
+ public void testShortcutIdTruncated() {
+ ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(),
+ String.join("", Collections.nCopies(Short.MAX_VALUE, "s"))).build();
+
+ assertTrue(
+ "id must be truncated to MAX_ID_LENGTH",
+ si.getId().length() <= ShortcutInfo.MAX_ID_LENGTH);
+ }
+
public void testShortcutInfoParcel() {
setCaller(CALLING_PACKAGE_1, USER_10);
ShortcutInfo si = parceled(new ShortcutInfo.Builder(mClientContext)
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 496a4cd..2f5896a 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -102,6 +102,7 @@
import android.app.PendingIntent;
import android.app.Person;
import android.app.RemoteInput;
+import android.app.RemoteInputHistoryItem;
import android.app.StatsManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
@@ -4244,10 +4245,36 @@
public void testVisitUris() throws Exception {
final Uri audioContents = Uri.parse("content://com.example/audio");
final Uri backgroundImage = Uri.parse("content://com.example/background");
+ final Icon personIcon1 = Icon.createWithContentUri("content://media/person1");
+ final Icon personIcon2 = Icon.createWithContentUri("content://media/person2");
+ final Icon personIcon3 = Icon.createWithContentUri("content://media/person3");
+ final Person person1 = new Person.Builder()
+ .setName("Messaging Person")
+ .setIcon(personIcon1)
+ .build();
+ final Person person2 = new Person.Builder()
+ .setName("People List Person 1")
+ .setIcon(personIcon2)
+ .build();
+ final Person person3 = new Person.Builder()
+ .setName("People List Person 2")
+ .setIcon(personIcon3)
+ .build();
+ final Uri historyUri1 = Uri.parse("content://com.example/history1");
+ final Uri historyUri2 = Uri.parse("content://com.example/history2");
+ final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1,
+ "a");
+ final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2,
+ "b");
Bundle extras = new Bundle();
extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents);
extras.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, backgroundImage.toString());
+ extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1);
+ extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST,
+ new ArrayList<>(Arrays.asList(person2, person3)));
+ extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
+ new RemoteInputHistoryItem[]{historyItem1, historyItem2});
Notification n = new Notification.Builder(mContext, "a")
.setContentTitle("notification with uris")
@@ -4259,6 +4286,11 @@
n.visitUris(visitor);
verify(visitor, times(1)).accept(eq(audioContents));
verify(visitor, times(1)).accept(eq(backgroundImage));
+ verify(visitor, times(1)).accept(eq(personIcon1.getUri()));
+ verify(visitor, times(1)).accept(eq(personIcon2.getUri()));
+ verify(visitor, times(1)).accept(eq(personIcon3.getUri()));
+ verify(visitor, times(1)).accept(eq(historyUri1));
+ verify(visitor, times(1)).accept(eq(historyUri2));
}
@Test