Add a mainline-accessible API to kill an app on sandbox death

This API can be accessed by mainline modules to kill a specific app
process when its associated sandbox dies. It takes in the IBinder value
of the corresponding IApplicationThread of the app to kill it.

REASON_DEPENDENCY_DIED and SUBREASON_SDK_SANDBOX_DIED are used in the
emitted AppProcessDied atom.

Bug: 261558210
Test: atest SdkSandboxLifecycleHostTest
Test: m statsd && statsd_testdrive 373 emits an atom with
SUBREASON_SDK_SANDBOX_DIED

Change-Id: Id37023eabaa5f734bb67bee07a0f779c355cc100
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 98c78fe..2596d93 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -80,6 +80,7 @@
   }
 
   public abstract class Context {
+    method @NonNull public android.os.IBinder getIApplicationThreadBinder();
     method @NonNull public android.os.UserHandle getUser();
     field public static final String PAC_PROXY_SERVICE = "pac_proxy";
     field public static final String TEST_NETWORK_SERVICE = "test_network";
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 871d15e..51ea04f 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -416,6 +416,15 @@
      */
     public static final int SUBREASON_UNDELIVERED_BROADCAST = 26;
 
+    /**
+     * The process was killed because its associated SDK sandbox process (where it had loaded SDKs)
+     * had died; this would be set only when the reason is {@link #REASON_DEPENDENCY_DIED}.
+     *
+     * For internal use only.
+     * @hide
+     */
+    public static final int SUBREASON_SDK_SANDBOX_DIED = 27;
+
     // If there is any OEM code which involves additional app kill reasons, it should
     // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 042bdd7..afef1241 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1999,6 +1999,13 @@
     }
 
     /** @hide */
+    @NonNull
+    @Override
+    public IBinder getIApplicationThreadBinder() {
+        return getIApplicationThread().asBinder();
+    }
+
+    /** @hide */
     @Override
     public Handler getMainThreadHandler() {
         return mMainThread.getHandler();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index df5a1ed..6d0b3bc 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -7346,6 +7346,18 @@
     }
 
     /**
+     * Get the binder object associated with the IApplicationThread of this Context.
+     *
+     * This can be used by a mainline module to uniquely identify a specific app process.
+     * @hide
+     */
+    @NonNull
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public IBinder getIApplicationThreadBinder() {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * @hide
      */
     public Handler getMainThreadHandler() {
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index a1646a1..a4bb6cc 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1251,6 +1251,14 @@
      * @hide
      */
     @Override
+    public IBinder getIApplicationThreadBinder() {
+        return mBase.getIApplicationThreadBinder();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
     public Handler getMainThreadHandler() {
         return mBase.getMainThreadHandler();
     }
diff --git a/services/api/current.txt b/services/api/current.txt
index da5b1fc..5d3c88c 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -40,6 +40,7 @@
   public interface ActivityManagerLocal {
     method public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, @NonNull String, int) throws android.os.RemoteException;
     method public boolean canStartForegroundService(int, int, @NonNull String);
+    method public void killSdkSandboxClientAppProcess(@NonNull android.os.IBinder);
   }
 
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerLocal.java b/services/core/java/com/android/server/am/ActivityManagerLocal.java
index 9f2cc7f..5175a31 100644
--- a/services/core/java/com/android/server/am/ActivityManagerLocal.java
+++ b/services/core/java/com/android/server/am/ActivityManagerLocal.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.IBinder;
 import android.os.RemoteException;
 
 /**
@@ -95,6 +96,15 @@
             throws RemoteException;
 
     /**
+     * Kill an app process associated with an SDK sandbox.
+     *
+     * @param clientApplicationThreadBinder binder value of the
+     *        {@link android.app.IApplicationThread} of a client app process associated with a
+     *        sandbox. This is obtained using {@link Context#getIApplicationThreadBinder()}.
+     */
+    void killSdkSandboxClientAppProcess(@NonNull IBinder clientApplicationThreadBinder);
+
+    /**
      * Start a foreground service delegate.
      * @param options foreground service delegate options.
      * @param connection a service connection served as callback to caller.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e7e2081..316e0d5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16940,6 +16940,20 @@
         }
 
         @Override
+        public void killSdkSandboxClientAppProcess(IBinder clientApplicationThreadBinder) {
+            synchronized (ActivityManagerService.this) {
+                ProcessRecord r = getRecordForAppLOSP(clientApplicationThreadBinder);
+                if (r != null) {
+                    r.killLocked(
+                            "sdk sandbox died",
+                            ApplicationExitInfo.REASON_DEPENDENCY_DIED,
+                            ApplicationExitInfo.SUBREASON_SDK_SANDBOX_DIED,
+                            true);
+                }
+            }
+        }
+
+        @Override
         public void onUserRemoved(@UserIdInt int userId) {
             // Clean up any ActivityTaskManager state (by telling it the user is stopped)
             mAtmInternal.onUserStopped(userId);