Merge "Add atom logging for intervention framework"
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index a954164..7877b65 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -40,6 +40,7 @@
 import android.app.GameState;
 import android.app.IGameManagerService;
 import android.app.IGameModeListener;
+import android.app.StatsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -76,6 +77,7 @@
 import android.util.AttributeSet;
 import android.util.KeyValueListParser;
 import android.util.Slog;
+import android.util.StatsEvent;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
@@ -104,6 +106,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Service to manage game related features.
@@ -932,6 +935,7 @@
         public void onBootPhase(int phase) {
             if (phase == PHASE_BOOT_COMPLETED) {
                 mService.onBootCompleted();
+                mService.registerStatsCallbacks();
             }
         }
 
@@ -1150,6 +1154,15 @@
         sendUserMessage(userId, WRITE_SETTINGS, "SET_GAME_MODE", WRITE_DELAY_MILLIS);
         sendUserMessage(userId, WRITE_GAME_MODE_INTERVENTION_LIST_FILE,
                 "SET_GAME_MODE", 0 /*delayMillis*/);
+        int gameUid = -1;
+        try {
+            gameUid = mPackageManager.getPackageUidAsUser(packageName, userId);
+        } catch (NameNotFoundException ex) {
+            Slog.d(TAG, "Cannot find the UID for package " + packageName + " under user " + userId);
+        }
+        FrameworkStatsLog.write(FrameworkStatsLog.GAME_MODE_CHANGED, gameUid,
+                Binder.getCallingUid(), gameModeToStatsdGameMode(fromGameMode),
+                gameModeToStatsdGameMode(gameMode));
     }
 
     /**
@@ -1364,11 +1377,21 @@
         }
         GamePackageConfiguration.GameModeConfiguration internalConfig =
                 configOverride.getOrAddDefaultGameModeConfiguration(GameManager.GAME_MODE_CUSTOM);
+        int gameUid = -1;
+        try {
+            gameUid = mPackageManager.getPackageUidAsUser(packageName, userId);
+        } catch (NameNotFoundException ex) {
+            Slog.d(TAG, "Cannot find the UID for package " + packageName + " under user " + userId);
+        }
+        FrameworkStatsLog.write(FrameworkStatsLog.GAME_MODE_CONFIGURATION_CHANGED, gameUid,
+                Binder.getCallingUid(), gameModeToStatsdGameMode(GameManager.GAME_MODE_CUSTOM),
+                internalConfig.getScaling(), gameModeConfig.getScalingFactor(),
+                internalConfig.getFps(), gameModeConfig.getFpsOverride());
         internalConfig.updateFromPublicGameModeConfig(gameModeConfig);
 
         Slog.i(TAG, "Updated custom game mode config for package: " + packageName
                 + " with FPS=" + internalConfig.getFps() + ";Scaling="
-                + internalConfig.getScaling());
+                + internalConfig.getScaling() + " under user " + userId);
     }
 
     /**
@@ -1629,11 +1652,6 @@
     public void resetGameModeConfigOverride(String packageName, @UserIdInt int userId,
             @GameMode int gameModeToReset) throws SecurityException {
         checkPermission(Manifest.permission.MANAGE_GAME_MODE);
-        final GamePackageConfiguration deviceConfig;
-        synchronized (mDeviceConfigLock) {
-            deviceConfig = mConfigs.get(packageName);
-        }
-
         // resets GamePackageConfiguration of a given packageName.
         // If a gameMode is specified, only reset the GameModeConfiguration of the gameMode.
         synchronized (mLock) {
@@ -1949,13 +1967,99 @@
         LocalServices.addService(GameManagerInternal.class, new LocalService());
     }
 
-    private String dumpDeviceConfigs() {
-        StringBuilder out = new StringBuilder();
-        for (String key : mConfigs.keySet()) {
-            out.append("[\nName: ").append(key)
-                    .append("\nConfig: ").append(mConfigs.get(key).toString()).append("\n]");
+    private void registerStatsCallbacks() {
+        final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
+        statsManager.setPullAtomCallback(
+                FrameworkStatsLog.GAME_MODE_INFO,
+                null, // use default PullAtomMetadata values
+                BackgroundThread.getExecutor(),
+                this::onPullAtom);
+        statsManager.setPullAtomCallback(
+                FrameworkStatsLog.GAME_MODE_CONFIGURATION,
+                null, // use default PullAtomMetadata values
+                BackgroundThread.getExecutor(),
+                this::onPullAtom);
+        statsManager.setPullAtomCallback(
+                FrameworkStatsLog.GAME_MODE_LISTENER,
+                null, // use default PullAtomMetadata values
+                BackgroundThread.getExecutor(),
+                this::onPullAtom);
+    }
+
+    private int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) {
+        if (atomTag == FrameworkStatsLog.GAME_MODE_INFO
+                || atomTag == FrameworkStatsLog.GAME_MODE_CONFIGURATION) {
+            int userId = ActivityManager.getCurrentUser();
+            Set<String> packages;
+            synchronized (mDeviceConfigLock) {
+                packages = mConfigs.keySet();
+            }
+            for (String p : packages) {
+                GamePackageConfiguration config = getConfig(p, userId);
+                if (config == null) {
+                    continue;
+                }
+                int uid = -1;
+                try {
+                    uid = mPackageManager.getPackageUidAsUser(p, userId);
+                } catch (NameNotFoundException ex) {
+                    Slog.d(TAG,
+                            "Cannot find UID for package " + p + " under user handle id " + userId);
+                }
+                if (atomTag == FrameworkStatsLog.GAME_MODE_INFO) {
+                    data.add(
+                            FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.GAME_MODE_INFO, uid,
+                                    gameModesToStatsdGameModes(config.getOptedInGameModes()),
+                                    gameModesToStatsdGameModes(config.getAvailableGameModes())));
+                } else if (atomTag == FrameworkStatsLog.GAME_MODE_CONFIGURATION) {
+                    for (int gameMode : config.getAvailableGameModes()) {
+                        GamePackageConfiguration.GameModeConfiguration modeConfig =
+                                config.getGameModeConfiguration(gameMode);
+                        if (modeConfig != null) {
+                            data.add(FrameworkStatsLog.buildStatsEvent(
+                                    FrameworkStatsLog.GAME_MODE_CONFIGURATION, uid,
+                                    gameModeToStatsdGameMode(gameMode), modeConfig.getFps(),
+                                    modeConfig.getScaling()));
+                        }
+                    }
+                }
+            }
+        } else if (atomTag == FrameworkStatsLog.GAME_MODE_LISTENER) {
+            synchronized (mGameModeListenerLock) {
+                data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.GAME_MODE_LISTENER,
+                        mGameModeListeners.size()));
+            }
         }
-        return out.toString();
+        return android.app.StatsManager.PULL_SUCCESS;
+    }
+
+    private static int[] gameModesToStatsdGameModes(int[] modes) {
+        if (modes == null) {
+            return null;
+        }
+        int[] statsdModes = new int[modes.length];
+        int i = 0;
+        for (int mode : modes) {
+            statsdModes[i++] = gameModeToStatsdGameMode(mode);
+        }
+        return statsdModes;
+    }
+
+    private static int gameModeToStatsdGameMode(int mode) {
+        switch (mode) {
+            case GameManager.GAME_MODE_BATTERY:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_BATTERY;
+            case GameManager.GAME_MODE_PERFORMANCE:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_PERFORMANCE;
+            case GameManager.GAME_MODE_CUSTOM:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_CUSTOM;
+            case GameManager.GAME_MODE_STANDARD:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_STANDARD;
+            case GameManager.GAME_MODE_UNSUPPORTED:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_UNSUPPORTED;
+            default:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_UNSPECIFIED;
+        }
     }
 
     private static int gameStateModeToStatsdGameState(int mode) {