CachedAppOptimizer: ensure binder is never frozen with app unfrozen

Unfreezing a binder interface after the app, as well as freezing it
before the app, opens a time window during wich the process is active
and yet synchrnous binder transactions would fail.

Unfreeze binder before the app, and similarly freeze it after freezing,
to ensure consistent states.

Bug: b/171239744
Test: verified correct working of the sequence by manually sending
synchronous messages during the critical intervals.

Change-Id: I5fad4cdf497a567aceb15b1fc3025b049c54983e
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 8112bb8..cd0d5b4 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -777,27 +777,27 @@
         long freezeTime = app.freezeUnfreezeTime;
 
         try {
+            freezeBinder(app.pid, false);
+        } catch (RuntimeException e) {
+            Slog.e(TAG_AM, "Unable to unfreeze binder for " + app.pid + " " + app.processName
+                    + ". Killing it");
+            app.kill("Unable to unfreeze",
+                    ApplicationExitInfo.REASON_OTHER,
+                    ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+            return;
+        }
+
+        try {
             Process.setProcessFrozen(app.pid, app.uid, false);
 
             app.freezeUnfreezeTime = SystemClock.uptimeMillis();
             app.frozen = false;
         } catch (Exception e) {
             Slog.e(TAG_AM, "Unable to unfreeze " + app.pid + " " + app.processName
-                    + ". Any related user experience might be hanged.");
+                    + ". This might cause inconsistency or UI hangs.");
         }
 
         if (!app.frozen) {
-            try {
-                freezeBinder(app.pid, false);
-            } catch (RuntimeException e) {
-                Slog.e(TAG_AM, "Unable to unfreeze binder for " + app.pid + " " + app.processName
-                        + ". Killing it");
-                app.kill("Unable to unfreeze",
-                        ApplicationExitInfo.REASON_OTHER,
-                        ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
-                return;
-            }
-
             if (DEBUG_FREEZER) {
                 Slog.d(TAG_AM, "sync unfroze " + app.pid + " " + app.processName);
             }
@@ -1110,14 +1110,6 @@
                     return;
                 }
 
-                try {
-                    freezeBinder(pid, true);
-                } catch (RuntimeException e) {
-                    // TODO: it might be preferable to kill the target pid in this case
-                    Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
-                    return;
-                }
-
                 if (pid == 0 || proc.frozen) {
                     // Already frozen or not a real process, either one being
                     // launched or one being killed
@@ -1146,6 +1138,15 @@
 
                 EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name);
 
+                try {
+                    freezeBinder(pid, true);
+                } catch (RuntimeException e) {
+                    Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
+                    proc.kill("Unable to freeze binder interface",
+                            ApplicationExitInfo.REASON_OTHER,
+                            ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+                }
+
                 // See above for why we're not taking mPhenotypeFlagLock here
                 if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
                     FrameworkStatsLog.write(FrameworkStatsLog.APP_FREEZE_CHANGED,