diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 8191d37bb6038..bbd3dca0689c2 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1264,7 +1264,7 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra // 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 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra 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 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* experimentIdsOut) { uid_t uid = IPCThreadState::self()->getCallingUid(); diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index a4e6d7fec4cc3..8d8514f8b455c 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -195,6 +195,14 @@ public: const int32_t state, const std::vector& 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. */ diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl index 311c86d08211d..a596fdcfd712e 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/core/java/android/os/IStatsManager.aidl @@ -218,6 +218,12 @@ interface IStatsManager { oneway void sendBinaryPushStateChangedAtom(in String trainName, in long trainVersionCode, 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. */ diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index cfc092cb78e88..f7077bb2a418b 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -23,7 +23,6 @@ import android.Manifest; 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 @@ public final class StatsLog extends StatsLogInternal { } 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 @@ public final class StatsLog extends StatsLogInternal { } } + /** + * 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 da1c413f05dae..9c19aeccd59a3 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -358,8 +358,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve 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()); } }