Add prepareProcessTermination to ICarWatchdogClient

- CarWatchdogManager is providing onPrepareProcessTermination.
- It is trigerred by CarWatchdogService through ICarWatchdogClient
interface, but the current ICarWatchdogClient doesn't have such method.

Bug: 150006093
Test: build okay, run "/vendor/bin/carwatchdog_testclient critical 10 -1
--verbose", and make sure there is a log "This process is being
terminated by car watchdog"

Change-Id: I24b52c1dc6b3af055ab3473d5a47f072a8b99029
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index d24e569..21ac3e6 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -107,7 +107,7 @@
     @GuardedBy("mLock")
     private final SparseArray<Boolean> mClientCheckInProgress = new SparseArray<>();
     @GuardedBy("mLock")
-    private final ArrayList<Integer> mClientsNotResponding = new ArrayList<>();
+    private final ArrayList<ClientInfo> mClientsNotResponding = new ArrayList<>();
     @GuardedBy("mMainHandler")
     private int mLastSessionId;
     @GuardedBy("mMainHandler")
@@ -324,14 +324,13 @@
         // and killed at the next response of CarWatchdogService to car watchdog daemon.
         SparseArray<ClientInfo> pingedClients = mPingedClientMap.get(timeout);
         synchronized (mLock) {
-            // Unhealthy clients are eventually removed from the list through binderDied when they
-            // are killed.
             for (int i = 0; i < pingedClients.size(); i++) {
                 ClientInfo clientInfo = pingedClients.valueAt(i);
                 if (mStoppedUser.get(clientInfo.userId)) {
                     continue;
                 }
-                mClientsNotResponding.add(clientInfo.pid);
+                mClientsNotResponding.add(clientInfo);
+                removeClientLocked(clientInfo.client.asBinder(), timeout);
             }
             mClientCheckInProgress.setValueAt(timeout, false);
         }
@@ -399,10 +398,22 @@
 
     private void reportHealthCheckResult(int sessionId) {
         int[] clientsNotResponding;
+        ArrayList<ClientInfo> clientsToNotify;
         synchronized (mLock) {
             clientsNotResponding = toIntArray(mClientsNotResponding);
+            clientsToNotify = new ArrayList<>(mClientsNotResponding);
             mClientsNotResponding.clear();
         }
+        for (int i = 0; i < clientsToNotify.size(); i++) {
+            ClientInfo clientInfo = clientsToNotify.get(i);
+            try {
+                clientInfo.client.prepareProcessTermination();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Notifying prepareProcessTermination to client(pid: " + clientInfo.pid
+                        + ") failed: " + e);
+            }
+        }
+
         try {
             mCarWatchdogDaemonHelper.tellMediatorAlive(mWatchdogClient, clientsNotResponding,
                     sessionId);
@@ -500,11 +511,11 @@
     }
 
     @NonNull
-    private int[] toIntArray(@NonNull ArrayList<Integer> list) {
+    private int[] toIntArray(@NonNull ArrayList<ClientInfo> list) {
         int size = list.size();
         int[] intArray = new int[size];
         for (int i = 0; i < size; i++) {
-            intArray[i] = list.get(i);
+            intArray[i] = list.get(i).pid;
         }
         return intArray;
     }
@@ -556,6 +567,11 @@
         }
 
         @Override
+        public void prepareProcessTermination() {
+            Log.w(TAG, "CarWatchdogService is about to be killed by car watchdog daemon");
+        }
+
+        @Override
         public int getInterfaceVersion() {
             return this.VERSION;
         }