Statsd: Add watchdog rollback to experiment ids

Stores experiment ids to disk for watchdog rollback initiate/success
events as discussed.

Test: gts in topic
Bug: 131768455
Change-Id: I32768fe5c5c21c43811e25d8f87faae0c8d82c1f
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 8191d37..bbd3dca 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1264,7 +1264,7 @@
     // This method only sends data, it does not receive it.
     pid_t pid = IPCThreadState::self()->getCallingPid();
     uid_t uid = IPCThreadState::self()->getCallingUid();
-        // Root, system, and shell always have access
+    // Root, system, and shell always have access
     if (uid != AID_ROOT && uid != AID_SYSTEM && uid != AID_SHELL) {
         // Caller must be granted these permissions
         if (!checkCallingPermission(String16(kPermissionDump))) {
@@ -1349,6 +1349,64 @@
     return Status::ok();
 }
 
+Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackTypeIn,
+                                                      const android::String16& packageNameIn,
+                                                      const int64_t packageVersionCodeIn) {
+    // Note: We skip the usage stats op check here since we do not have a package name.
+    // This is ok since we are overloading the usage_stats permission.
+    // This method only sends data, it does not receive it.
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    // Root, system, and shell always have access
+    if (uid != AID_ROOT && uid != AID_SYSTEM && uid != AID_SHELL) {
+        // Caller must be granted these permissions
+        if (!checkCallingPermission(String16(kPermissionDump))) {
+            return exception(binder::Status::EX_SECURITY,
+                             StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
+                                          kPermissionDump));
+        }
+        if (!checkCallingPermission(String16(kPermissionUsage))) {
+            return exception(binder::Status::EX_SECURITY,
+                             StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
+                                          kPermissionUsage));
+        }
+    }
+
+    android::util::stats_write(android::util::WATCHDOG_ROLLBACK_OCCURRED,
+            rollbackTypeIn, String8(packageNameIn).string(), packageVersionCodeIn);
+
+    // Fast return to save disk read.
+    if (rollbackTypeIn != android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS
+            && rollbackTypeIn !=
+                    android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE) {
+        return Status::ok();
+    }
+
+    bool readTrainInfoSuccess = false;
+    InstallTrainInfo trainInfoOnDisk;
+    readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfoOnDisk);
+
+    if (!readTrainInfoSuccess) {
+        return Status::ok();
+    }
+    std::vector<int64_t> experimentIds = trainInfoOnDisk.experimentIds;
+    if (experimentIds.empty()) {
+        return Status::ok();
+    }
+    switch (rollbackTypeIn) {
+        case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
+            experimentIds.push_back(experimentIds[0] + 4);
+            break;
+        case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
+            experimentIds.push_back(experimentIds[0] + 5);
+            break;
+    }
+    StorageManager::writeTrainInfo(trainInfoOnDisk.trainVersionCode, trainInfoOnDisk.trainName,
+            trainInfoOnDisk.status, experimentIds);
+    return Status::ok();
+}
+
+
 Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) {
     uid_t uid = IPCThreadState::self()->getCallingUid();
 
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index a4e6d7f..8d8514f 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -196,6 +196,14 @@
             const std::vector<int64_t>& experimentIdsIn) override;
 
     /**
+     * Binder call to log WatchdogRollbackOccurred atom.
+     */
+    virtual Status sendWatchdogRollbackOccurredAtom(
+            const int32_t rollbackTypeIn,
+            const android::String16& packageNameIn,
+            const int64_t packageVersionCodeIn) override;
+
+    /**
      * Binder call to get registered experiment IDs.
      */
     virtual Status getRegisteredExperimentIds(std::vector<int64_t>* expIdsOut);
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 311c86d..a596fdc 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -219,6 +219,12 @@
          in int options, in int state, in long[] experimentId);
 
     /**
+     * Logs an event for watchdog rollbacks.
+     */
+     oneway void sendWatchdogRollbackOccurredAtom(in int rollbackType, in String packageName,
+         in long packageVersionCode);
+
+    /**
      * Returns the most recently registered experiment IDs.
      */
     long[] getRegisteredExperimentIds();
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index cfc092c..f7077bb 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -23,7 +23,6 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.app.IActivityManager;
 import android.content.Context;
 import android.os.IStatsManager;
 import android.os.RemoteException;
@@ -159,10 +158,6 @@
                     }
                     return false;
                 }
-                int userId = IActivityManager.Stub.asInterface(
-                        ServiceManager.getService("activity"))
-                        .getCurrentUser()
-                        .id;
                 service.sendBinaryPushStateChangedAtom(
                         trainName, trainVersionCode, options, state, experimentIds);
                 return true;
@@ -178,6 +173,46 @@
         }
     }
 
+    /**
+     * Logs an event for watchdog rollbacks.
+     *
+     * @param rollbackType          state of the rollback.
+     * @param packageName           package name being rolled back.
+     * @param packageVersionCode    version of the package being rolled back.
+     *
+     * @return True if the log request was sent to statsd.
+     *
+     * @hide
+     */
+    @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
+    public static boolean logWatchdogRollbackOccurred(int rollbackType, String packageName,
+            long packageVersionCode) {
+        synchronized (sLogLock) {
+            try {
+                IStatsManager service = getIStatsManagerLocked();
+                if (service == null) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Failed to find statsd when logging event");
+                    }
+                    return false;
+                }
+
+                service.sendWatchdogRollbackOccurredAtom(rollbackType, packageName,
+                        packageVersionCode);
+                return true;
+            } catch (RemoteException e) {
+                sService = null;
+                if (DEBUG) {
+                    Slog.d(TAG,
+                            "Failed to connect to StatsCompanionService when logging "
+                                    + "WatchdogRollbackOccurred");
+                }
+                return false;
+            }
+        }
+    }
+
+
     private static IStatsManager getIStatsManagerLocked() throws RemoteException {
         if (sService != null) {
             return sService;
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index bcef66c..9272e96 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -338,8 +338,8 @@
     private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type) {
         Slog.i(TAG, "Watchdog event occurred of type: " + type);
         if (moduleMetadataPackage != null) {
-            StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, type,
-                    moduleMetadataPackage.getPackageName(), moduleMetadataPackage.getVersionCode());
+            StatsLog.logWatchdogRollbackOccurred(type, moduleMetadataPackage.getPackageName(),
+                    moduleMetadataPackage.getVersionCode());
         }
     }