Merge "RESTRICT AUTOMERGE" into oc-mr1-dev
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 1811748..d29a332 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -266,7 +266,8 @@
boolean isImmersive(in IBinder token);
void setImmersive(in IBinder token, boolean immersive);
boolean isTopActivityImmersive();
- void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message);
+ void crashApplication(int uid, int initialPid, in String packageName, int userId,
+ in String message, boolean force);
String getProviderMimeType(in Uri uri, int userId);
IBinder newUriPermissionOwner(in String name);
void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 98be5b2..210f9f5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2843,6 +2843,11 @@
<permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to manage the companion devices.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_COMPANION_DEVICES"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to use SurfaceFlinger's low level features.
<p>Not for use by third-party applications.
@hide
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index f2f01cf..aaa4626 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -624,6 +624,11 @@
+ "associate USER_ID PACKAGE MAC_ADDRESS\n"
+ "disassociate USER_ID PACKAGE MAC_ADDRESS";
+ ShellCmd() {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_COMPANION_DEVICES, "ShellCmd");
+ }
+
@Override
public int onCommand(String cmd) {
switch (cmd) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 9d823a7..8e0bf6f 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -653,6 +653,15 @@
}
}
+ void killMisbehavingService(ServiceRecord r,
+ int appUid, int appPid, String localPackageName) {
+ synchronized (mAm) {
+ stopServiceLocked(r);
+ mAm.crashApplication(appUid, appPid, localPackageName, -1,
+ "Bad notification for startForeground", true /*force*/);
+ }
+ }
+
IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) {
ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(),
@@ -3391,7 +3400,8 @@
void serviceForegroundCrash(ProcessRecord app) {
mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId,
- "Context.startForegroundService() did not then call Service.startForeground()");
+ "Context.startForegroundService() did not then call Service.startForeground()",
+ false /*force*/);
}
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b4c18b1..c917530 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5141,7 +5141,7 @@
@Override
public void crashApplication(int uid, int initialPid, String packageName, int userId,
- String message) {
+ String message, boolean force) {
if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: crashApplication() from pid="
@@ -5153,7 +5153,8 @@
}
synchronized(this) {
- mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message);
+ mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId,
+ message, force);
}
}
@@ -6916,7 +6917,7 @@
}
}
- private final boolean attachApplicationLocked(IApplicationThread thread,
+ private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid) {
// Find the application record that is being attached... either via
@@ -7221,6 +7222,9 @@
@Override
public final void attachApplication(IApplicationThread thread) {
+ if (thread == null) {
+ throw new SecurityException("Invalid application interface");
+ }
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 8488e52..9575fdd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -921,7 +921,7 @@
} catch (NumberFormatException e) {
packageName = arg;
}
- mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash");
+ mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash", false);
return 0;
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1998605..c1ea022 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3961,6 +3961,11 @@
final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
Intent resultData) {
+ if (srec.app == null || srec.app.thread == null) {
+ // Nothing to do if the caller is not attached, because this method should be called
+ // from an alive activity.
+ return false;
+ }
final TaskRecord task = srec.getTask();
final ArrayList<ActivityRecord> activities = task.mActivities;
final int start = activities.indexOf(srec);
@@ -4012,22 +4017,22 @@
}
if (parent != null && foundParentInTask) {
+ final int callingUid = srec.info.applicationInfo.uid;
final int parentLaunchMode = parent.info.launchMode;
final int destIntentFlags = destIntent.getFlags();
if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
(destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
- parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent,
- srec.packageName);
+ parent.deliverNewIntentLocked(callingUid, destIntent, srec.packageName);
} else {
try {
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
destIntent.getComponent(), 0, srec.userId);
int res = mService.mActivityStarter.startActivityLocked(srec.app.thread,
destIntent, null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null,
- null, parent.appToken, null, 0, -1, parent.launchedFromUid,
- parent.launchedFromPackage, -1, parent.launchedFromUid, 0, null,
+ null, parent.appToken, null, 0, -1, callingUid,
+ srec.packageName, -1, callingUid, 0, null,
false, true, null, null, "navigateUpTo");
foundParentInTask = res == ActivityManager.START_SUCCESS;
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index fa2e04f..aec552d 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -940,6 +940,8 @@
} else {
callingPid = callingUid = -1;
}
+ boolean forceNewTask = false;
+ final int filterCallingUid = callingUid >= 0 ? callingUid : realCallingUid;
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mService) {
@@ -959,6 +961,9 @@
// Don't modify the client's object!
intent = new Intent(intent);
+ if (forceNewTask) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
@@ -984,7 +989,17 @@
return res;
}
- resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
+ final ActivityRecord started = outActivity[0];
+ if (started != null && started.getUid() == filterCallingUid) {
+ // Only the started activity which has the same uid as the source caller can
+ // be the caller of next activity.
+ resultTo = started.appToken;
+ forceNewTask = false;
+ } else {
+ // Different apps not adjacent to the caller are forced to be new task.
+ resultTo = null;
+ forceNewTask = true;
+ }
}
}
} finally {
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index a842724..a7954bb 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -243,20 +243,24 @@
}
void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) {
- app.crashing = false;
- app.crashingReport = null;
- app.notResponding = false;
- app.notRespondingReport = null;
if (app.anrDialog == fromDialog) {
app.anrDialog = null;
}
if (app.waitDialog == fromDialog) {
app.waitDialog = null;
}
+ killAppImmediateLocked(app, "user-terminated", "user request after error");
+ }
+
+ private void killAppImmediateLocked(ProcessRecord app, String reason, String killReason) {
+ app.crashing = false;
+ app.crashingReport = null;
+ app.notResponding = false;
+ app.notRespondingReport = null;
if (app.pid > 0 && app.pid != MY_PID) {
- handleAppCrashLocked(app, "user-terminated" /*reason*/,
+ handleAppCrashLocked(app, reason,
null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/);
- app.kill("user request after error", true);
+ app.kill(killReason, true);
}
}
@@ -270,7 +274,7 @@
* @param message
*/
void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId,
- String message) {
+ String message, boolean force) {
ProcessRecord proc = null;
// Figure out which process to kill. We don't trust that initialPid
@@ -303,6 +307,14 @@
}
proc.scheduleCrash(message);
+ if (force) {
+ // If the app is responsive, the scheduled crash will happen as expected
+ // and then the delayed summary kill will be a no-op.
+ final ProcessRecord p = proc;
+ mService.mHandler.postDelayed(
+ () -> killAppImmediateLocked(p, "forced", "killed for invalid state"),
+ 5000L);
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 16995e5..f87ba71 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -453,6 +453,7 @@
final String localPackageName = packageName;
final int localForegroundId = foregroundId;
final Notification _foregroundNoti = foregroundNoti;
+ final ServiceRecord record = this;
ams.mHandler.post(new Runnable() {
public void run() {
NotificationManagerInternal nm = LocalServices.getService(
@@ -551,10 +552,8 @@
Slog.w(TAG, "Error showing notification for service", e);
// If it gave us a garbage notification, it doesn't
// get to be foreground.
- ams.setServiceForeground(name, ServiceRecord.this,
- 0, null, 0);
- ams.crashApplication(appUid, appPid, localPackageName, -1,
- "Bad notification for startForeground: " + e);
+ ams.mServices.killMisbehavingService(record,
+ appUid, appPid, localPackageName);
}
}
});
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5df6083b..797ce37 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -714,18 +714,23 @@
@Override
public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
int uid, int initialPid, String message, int userId) {
- Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
- + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
+ final boolean fgService;
+ synchronized (mNotificationLock) {
+ NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
+ fgService = r != null
+ && (r.getNotification().flags&Notification.FLAG_FOREGROUND_SERVICE) != 0;
+ }
cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
REASON_ERROR, null);
- long ident = Binder.clearCallingIdentity();
- try {
- ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
- "Bad notification posted from package " + pkg
- + ": " + message);
- } catch (RemoteException e) {
+ if (fgService) {
+ // Still crash for foreground services, preventing the not-crash behaviour abused
+ // by apps to give us a garbage notification and silently start a fg service.
+ Binder.withCleanCallingIdentity(
+ () -> mAm.crashApplication(uid, initialPid, pkg, -1,
+ "Bad notification(tag=" + tag + ", id=" + id + ") posted from package "
+ + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): "
+ + message, true /* force */));
}
- Binder.restoreCallingIdentity(ident);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 819acfe..db3b767 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -19061,47 +19061,35 @@
int count = 0;
final String packageName = pkg.packageName;
- boolean handlesWebUris = false;
- final boolean alreadyVerified;
synchronized (mPackages) {
// If this is a new install and we see that we've already run verification for this
// package, we have nothing to do: it means the state was restored from backup.
- final IntentFilterVerificationInfo ivi =
- mSettings.getIntentFilterVerificationLPr(packageName);
- alreadyVerified = (ivi != null);
- if (!replacing && alreadyVerified) {
- if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.i(TAG, "Package " + packageName + " already verified: status="
- + ivi.getStatusString());
+ if (!replacing) {
+ IntentFilterVerificationInfo ivi =
+ mSettings.getIntentFilterVerificationLPr(packageName);
+ if (ivi != null) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.i(TAG, "Package " + packageName+ " already verified: status="
+ + ivi.getStatusString());
+ }
+ return;
}
- return;
}
- // If any filters need to be verified, then all need to be. In addition, we need to
- // know whether an updating app has any web navigation intent filters, to re-
- // examine handling policy even if not re-verifying.
+ // If any filters need to be verified, then all need to be.
boolean needToVerify = false;
for (PackageParser.Activity a : pkg.activities) {
for (ActivityIntentInfo filter : a.intents) {
- if (filter.handlesWebUris(true)) {
- handlesWebUris = true;
- }
if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.d(TAG, "Intent filter needs verification, so processing all filters");
}
needToVerify = true;
- // It's safe to break out here because filter.needsVerification()
- // can only be true if filter.handlesWebUris(true) returns true, so
- // we've already noted that.
break;
}
}
}
- // Note whether this app publishes any web navigation handling support at all,
- // and whether there are any web-nav filters that fit the profile for running
- // a verification pass now.
if (needToVerify) {
final int verificationId = mIntentFilterVerificationToken++;
for (PackageParser.Activity a : pkg.activities) {
@@ -19119,23 +19107,13 @@
}
if (count > 0) {
- // count > 0 means that we're running a full verification pass
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count
+ " IntentFilter verification" + (count > 1 ? "s" : "")
+ " for userId:" + userId);
mIntentFilterVerifier.startVerifications(userId);
- } else if (alreadyVerified && handlesWebUris) {
- // App used autoVerify in the past, no longer does, but still handles web
- // navigation starts.
- if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy");
- }
- synchronized (mPackages) {
- clearIntentFilterVerificationsLPw(packageName, userId);
- }
} else {
if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG, "No web filters or no prior verify policy for " + packageName);
+ Slog.d(TAG, "No filters or not all autoVerify for " + packageName);
}
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 0e1f3c2..56835f6 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1380,7 +1380,6 @@
return false;
}
ps.clearDomainVerificationStatusForUser(userId);
- ps.setIntentFilterVerificationInfo(null);
return true;
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 02fba08..33174b2 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -122,4 +122,17 @@
assertEquals(task.getTopActivity(true /* includeOverlays */), taskOverlay);
assertNotNull(result.r);
}
+
+ @Test
+ public void testNavigateUpTo() {
+ final ActivityManagerService service = createActivityManagerService();
+ final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
+ final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
+ activityRecord.app = new ProcessRecord(null, activityRecord.appInfo,
+ activityRecord.processName, activityRecord.getUid());
+ final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID);
+ // No-op if the source activity record doesn't have attached process (app.thread == null).
+ assertFalse(testStack.navigateUpToLocked(activityRecord, activityRecord.intent,
+ 0 /* resultCode */, null /* resultData */));
+ }
}