diff options
10 files changed, 123 insertions, 17 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e596e7c2ab06..e50432eaa299 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -236,12 +236,6 @@ import java.util.concurrent.atomic.AtomicBoolean;  import java.util.concurrent.atomic.AtomicInteger;  import java.util.function.Consumer; -final class RemoteServiceException extends AndroidRuntimeException { -    public RemoteServiceException(String msg) { -        super(msg); -    } -} -  /**   * This manages the execution of the main thread in an   * application process, scheduling and executing activities, @@ -1274,8 +1268,9 @@ public final class ActivityThread extends ClientTransactionHandler              sendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd);          } -        public void scheduleCrash(String msg) { -            sendMessage(H.SCHEDULE_CRASH, msg); +        @Override +        public void scheduleCrash(String msg, int typeId) { +            sendMessage(H.SCHEDULE_CRASH, msg, typeId);          }          public void dumpActivity(ParcelFileDescriptor pfd, IBinder activitytoken, @@ -1892,6 +1887,17 @@ public final class ActivityThread extends ClientTransactionHandler          }      } +    private void throwRemoteServiceException(String message, int typeId) { +        // Use a switch to ensure all the type IDs are unique. +        switch (typeId) { +            case ForegroundServiceDidNotStartInTimeException.TYPE_ID: // 1 +                throw new ForegroundServiceDidNotStartInTimeException(message); +            case RemoteServiceException.TYPE_ID: // 0 +            default: +                throw new RemoteServiceException(message); +        } +    } +      class H extends Handler {          public static final int BIND_APPLICATION        = 110;          @UnsupportedAppUsage @@ -2105,7 +2111,8 @@ public final class ActivityThread extends ClientTransactionHandler                      Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                      break;                  case SCHEDULE_CRASH: -                    throw new RemoteServiceException((String)msg.obj); +                    throwRemoteServiceException((String) msg.obj, msg.arg1); +                    break;                  case DUMP_HEAP:                      handleDumpHeap((DumpHeapData) msg.obj);                      break; diff --git a/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java b/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java new file mode 100644 index 000000000000..364291e69ad6 --- /dev/null +++ b/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java @@ -0,0 +1,33 @@ +/* + * 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; + +/** + * Exception used to crash an app process when it didn't call {@link Service#startForeground} + * in time after the service was started with + * {@link android.content.Context#startForegroundService}. + * + * @hide + */ +public class ForegroundServiceDidNotStartInTimeException extends RemoteServiceException { +    /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */ +    public static final int TYPE_ID = 1; + +    public ForegroundServiceDidNotStartInTimeException(String msg) { +        super(msg); +    } +} diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 1b8eb8add791..f9279da172a0 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -321,6 +321,8 @@ interface IActivityManager {      boolean isTopActivityImmersive();      void crashApplication(int uid, int initialPid, in String packageName, int userId,              in String message, boolean force); +    void crashApplicationWithType(int uid, int initialPid, in String packageName, int userId, +            in String message, boolean force, int exceptionTypeId);      /** @deprecated -- use getProviderMimeTypeAsync */      @UnsupportedAppUsage(maxTargetSdk = 29, publicAlternatives =              "Use {@link android.content.ContentResolver#getType} public API instead.") diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index b5294d5b6f4e..78e7ce8c594e 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -106,7 +106,7 @@ oneway interface IApplicationThread {      void scheduleOnNewActivityOptions(IBinder token, in Bundle options);      void scheduleSuicide();      void dispatchPackageBroadcast(int cmd, in String[] packages); -    void scheduleCrash(in String msg); +    void scheduleCrash(in String msg, int typeId);      void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String path,              in ParcelFileDescriptor fd, in RemoteCallback finishCallback);      void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix, diff --git a/core/java/android/app/RemoteServiceException.java b/core/java/android/app/RemoteServiceException.java new file mode 100644 index 000000000000..4b32463e2996 --- /dev/null +++ b/core/java/android/app/RemoteServiceException.java @@ -0,0 +1,38 @@ +/* + * 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.util.AndroidRuntimeException; + +/** + * Exception used by {@link ActivityThread} to crash an app process. + * + * @hide + */ +public class RemoteServiceException extends AndroidRuntimeException { +    /** +     * The type ID passed to {@link IApplicationThread#scheduleCrash}. +     * +     * Assign a unique ID to each subclass. See the above method for the numbers that are already +     * taken. +     */ +    public static final int TYPE_ID = 0; + +    public RemoteServiceException(String msg) { +        super(msg); +    } +} diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index f47fa39e7dc8..4dbdc606497e 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -531,7 +531,7 @@ public class TransactionParcelTests {          }          @Override -        public void scheduleCrash(String s) throws RemoteException { +        public void scheduleCrash(String s, int i) throws RemoteException {          }          @Override diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index c1ab6cc89eac..c7f2f43db131 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -78,6 +78,7 @@ import android.app.ActivityManagerInternal;  import android.app.ActivityThread;  import android.app.AppGlobals;  import android.app.AppOpsManager; +import android.app.ForegroundServiceDidNotStartInTimeException;  import android.app.ForegroundServiceStartNotAllowedException;  import android.app.IApplicationThread;  import android.app.IServiceConnection; @@ -4988,9 +4989,10 @@ public final class ActiveServices {      }      void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) { -        mAm.crashApplication(app.uid, app.getPid(), app.info.packageName, app.userId, +        mAm.crashApplicationWithType(app.uid, app.getPid(), app.info.packageName, app.userId,                  "Context.startForegroundService() did not then call Service.startForeground(): " -                    + serviceRecord, false /*force*/); +                    + serviceRecord, false /*force*/, +                ForegroundServiceDidNotStartInTimeException.TYPE_ID);      }      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 7dc39b34c88a..ac042a780a36 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -179,6 +179,7 @@ import android.app.PendingIntent;  import android.app.ProcessMemoryState;  import android.app.ProfilerInfo;  import android.app.PropertyInvalidatedCache; +import android.app.RemoteServiceException;  import android.app.SyncNotedAppOp;  import android.app.WaitResult;  import android.app.backup.BackupManager.OperationType; @@ -2935,6 +2936,13 @@ public class ActivityManagerService extends IActivityManager.Stub      @Override      public void crashApplication(int uid, int initialPid, String packageName, int userId,              String message, boolean force) { +        crashApplicationWithType(uid, initialPid, packageName, userId, message, force, +                RemoteServiceException.TYPE_ID); +    } + +    @Override +    public void crashApplicationWithType(int uid, int initialPid, String packageName, int userId, +            String message, boolean force, int exceptionTypeId) {          if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)                  != PackageManager.PERMISSION_GRANTED) {              String msg = "Permission Denial: crashApplication() from pid=" @@ -2947,7 +2955,7 @@ public class ActivityManagerService extends IActivityManager.Stub          synchronized(this) {              mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, -                    message, force); +                    message, force, exceptionTypeId);          }      } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 3602f44cd785..5a59eabde6f0 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -486,7 +486,7 @@ class AppErrors {       * @param message       */      void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId, -            String message, boolean force) { +            String message, boolean force, int exceptionTypeId) {          ProcessRecord proc = null;          // Figure out which process to kill.  We don't trust that initialPid @@ -518,7 +518,7 @@ class AppErrors {              return;          } -        proc.scheduleCrashLocked(message); +        proc.scheduleCrashLocked(message, exceptionTypeId);          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. diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index ed136afcc592..9e94d4aa2c0f 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -26,6 +26,7 @@ import android.app.ApplicationExitInfo;  import android.app.ApplicationExitInfo.Reason;  import android.app.ApplicationExitInfo.SubReason;  import android.app.IApplicationThread; +import android.app.RemoteServiceException;  import android.content.pm.ApplicationInfo;  import android.content.pm.ProcessInfo;  import android.content.pm.VersionedPackage; @@ -949,6 +950,21 @@ class ProcessRecord implements WindowProcessListener {      @GuardedBy("mService")      void scheduleCrashLocked(String message) { +        scheduleCrashLocked(message, RemoteServiceException.TYPE_ID); +    } + +    /** +     * Let an app process throw an exception on a binder thread, which typically crashes the +     * process, unless it has an unhandled exception handler. +     * +     * See {@link ActivityThread#throwRemoteServiceException}. +     * +     * @param message exception message +     * @param exceptionTypeId ID defined in {@link android.app.RemoteServiceException} or one +     *                        of its subclasses. +     */ +    @GuardedBy("mService") +    void scheduleCrashLocked(String message, int exceptionTypeId) {          // Checking killedbyAm should keep it from showing the crash dialog if the process          // was already dead for a good / normal reason.          if (!mKilledByAm) { @@ -959,7 +975,7 @@ class ProcessRecord implements WindowProcessListener {                  }                  final long ident = Binder.clearCallingIdentity();                  try { -                    mThread.scheduleCrash(message); +                    mThread.scheduleCrash(message, exceptionTypeId);                  } catch (RemoteException e) {                      // If it's already dead our work is done. If it's wedged just kill it.                      // We won't get the crash dialog or the error reporting.  |