diff --git a/apex/statsd/aidl/android/os/IPullAtomCallback.aidl b/apex/statsd/aidl/android/os/IPullAtomCallback.aidl index 88d3c3e46ff5c..ff0b97bb5b848 100644 --- a/apex/statsd/aidl/android/os/IPullAtomCallback.aidl +++ b/apex/statsd/aidl/android/os/IPullAtomCallback.aidl @@ -26,6 +26,6 @@ interface IPullAtomCallback { /** * Initiate a request for a pull for an atom. */ - void onPullAtom(int atomTag, IPullAtomResultReceiver resultReceiver); + oneway void onPullAtom(int atomTag, IPullAtomResultReceiver resultReceiver); } diff --git a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl index 22a25374e0645..5a6118ef81ca3 100644 --- a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl +++ b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl @@ -90,4 +90,7 @@ interface IStatsCompanionService { /** Tells StatsCompanionService to tell statsd to register a puller for the given atom id */ oneway void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs, in int[] additiveFields, IPullAtomCallback pullerCallback); + + /** Tells StatsCompanionService to tell statsd to unregister a puller for the given atom id */ + oneway void unregisterPullAtomCallback(int atomTag); } diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl index cffc6ce6e4df6..cce79fae75879 100644 --- a/apex/statsd/aidl/android/os/IStatsd.aidl +++ b/apex/statsd/aidl/android/os/IStatsd.aidl @@ -215,6 +215,11 @@ interface IStatsd { */ oneway void unregisterPullerCallback(int atomTag, String packageName); + /** + * Unregisters any pullAtomCallback for the given uid/atom. + */ + oneway void unregisterPullAtomCallback(int uid, int atomTag); + /** * The install requires staging. */ diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index c5fd3f2025e75..7ed51caf23dd7 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -2752,6 +2752,30 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } + @Override + public void unregisterPullAtomCallback(int atomTag) { + synchronized (sStatsdLock) { + // Always remove the puller in SCS. + // If statsd is down, we will not register it when it comes back up. + int callingUid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); + PullerKey key = new PullerKey(callingUid, atomTag); + mPullers.remove(key); + + if (sStatsd == null) { + Slog.w(TAG, "Could not access statsd for registering puller for atom " + atomTag); + return; + } + try { + sStatsd.unregisterPullAtomCallback(callingUid, atomTag); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to access statsd to register puller for atom " + atomTag); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } + // Statsd related code /** diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 4d38ba03b1df2..bb3a094af34a1 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1320,6 +1320,13 @@ Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& p return Status::ok(); } +Status StatsService::unregisterPullAtomCallback(int32_t uid, int32_t atomTag) { + ENFORCE_UID(AID_SYSTEM); + VLOG("StatsService::unregisterPullAtomCallback called."); + mPullerManager->UnregisterPullAtomCallback(uid, atomTag); + return Status::ok(); +} + Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& trainNameIn, const int64_t trainVersionCodeIn, const int options, diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 9abf415ad91f3..de55ca9c38cd1 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -198,6 +198,11 @@ public: */ virtual Status unregisterPullerCallback(int32_t atomTag, const String16& packageName) override; + /** + * Binder call to unregister any existing callback for the given uid and atom. + */ + virtual Status unregisterPullAtomCallback(int32_t uid, int32_t atomTag) override; + /** * Binder call to log BinaryPushStateChanged atom. */ diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp index 3c6bc2db1d621..883bd28a4d130 100644 --- a/cmds/statsd/src/external/StatsPuller.cpp +++ b/cmds/statsd/src/external/StatsPuller.cpp @@ -47,6 +47,7 @@ bool StatsPuller::Pull(std::vector>* data) { if (mHasGoodData) { (*data) = mCachedData; StatsdStats::getInstance().notePullFromCache(mTagId); + } return mHasGoodData; } diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index f913118385a37..50896f84da43b 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -294,6 +294,11 @@ StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { } bool StatsPullerManager::Pull(int tagId, vector>* data) { + AutoMutex _l(mLock); + return PullLocked(tagId, data); +} + +bool StatsPullerManager::PullLocked(int tagId, vector>* data) { VLOG("Initiating pulling %d", tagId); if (kAllPullAtomInfo.find({.atomTag = tagId}) != kAllPullAtomInfo.end()) { @@ -422,7 +427,7 @@ void StatsPullerManager::OnAlarmFired(int64_t elapsedTimeNs) { for (const auto& pullInfo : needToPull) { vector> data; - bool pullSuccess = Pull(pullInfo.first, &data); + bool pullSuccess = PullLocked(pullInfo.first, &data); if (pullSuccess) { StatsdStats::getInstance().notePullDelay( pullInfo.first, getElapsedRealtimeNs() - elapsedTimeNs); @@ -522,6 +527,12 @@ void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) { kAllPullAtomInfo.erase({.atomTag = atomTag}); } +void StatsPullerManager::UnregisterPullAtomCallback(const int uid, const int32_t atomTag) { + AutoMutex _l(mLock); + StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/false); + kAllPullAtomInfo.erase({.atomTag = atomTag}); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index 1bd9f92e4448d..349fd47b6c9d7 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -125,6 +125,8 @@ public: void UnregisterPullerCallback(int32_t atomTag); + void UnregisterPullAtomCallback(const int uid, const int32_t atomTag); + static std::map kAllPullAtomInfo; private: @@ -139,6 +141,8 @@ private: // mapping from simple matcher tagId to receivers std::map> mReceivers; + bool PullLocked(int tagId, vector>* data); + // locks for data receiver and StatsCompanionService changes Mutex mLock; diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java index cd855cf134d94..2d851e0abe6d8 100644 --- a/core/java/android/app/StatsManager.java +++ b/core/java/android/app/StatsManager.java @@ -107,6 +107,20 @@ public final class StatsManager { */ public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED"; + // Pull atom callback return codes. + /** + * Value indicating that this pull was successful and that the result should be used. + * + * @hide + **/ + public static final int PULL_SUCCESS = 0; + + /** + * Value indicating that this pull was unsuccessful and that the result should not be used. + * @hide + **/ + public static final int PULL_SKIP = 1; + private static final long DEFAULT_COOL_DOWN_NS = 1_000_000_000L; // 1 second. private static final long DEFAULT_TIMEOUT_NS = 10_000_000_000L; // 10 seconds. @@ -508,13 +522,11 @@ public final class StatsManager { * additive fields for mapping isolated to host uids. * @param callback The callback to be invoked when the stats service pulls the atom. * @param executor The executor in which to run the callback - * @throws RemoteException if unsuccessful due to failing to connect to system server. * * @hide */ public void registerPullAtomCallback(int atomTag, @Nullable PullAtomMetadata metadata, - @NonNull StatsPullAtomCallback callback, @NonNull Executor executor) - throws RemoteException, SecurityException { + @NonNull StatsPullAtomCallback callback, @NonNull Executor executor) { long coolDownNs = metadata == null ? DEFAULT_COOL_DOWN_NS : metadata.mCoolDownNs; long timeoutNs = metadata == null ? DEFAULT_TIMEOUT_NS : metadata.mTimeoutNs; int[] additiveFields = metadata == null ? new int[0] : metadata.mAdditiveFields; @@ -522,10 +534,34 @@ public final class StatsManager { additiveFields = new int[0]; } synchronized (sLock) { - IStatsCompanionService service = getIStatsCompanionServiceLocked(); - PullAtomCallbackInternal rec = + try { + IStatsCompanionService service = getIStatsCompanionServiceLocked(); + PullAtomCallbackInternal rec = new PullAtomCallbackInternal(atomTag, callback, executor); - service.registerPullAtomCallback(atomTag, coolDownNs, timeoutNs, additiveFields, rec); + service.registerPullAtomCallback(atomTag, coolDownNs, timeoutNs, additiveFields, + rec); + } catch (RemoteException e) { + throw new RuntimeException("Unable to register pull callback", e); + } + } + } + + /** + * Unregisters a callback for an atom when that atom is to be pulled. Note that any ongoing + * pulls will still occur. + * + * @param atomTag The tag of the atom of which to unregister + * + * @hide + */ + public void unregisterPullAtomCallback(int atomTag) { + synchronized (sLock) { + try { + IStatsCompanionService service = getIStatsCompanionServiceLocked(); + service.unregisterPullAtomCallback(atomTag); + } catch (RemoteException e) { + throw new RuntimeException("Unable to unregister pull atom callback"); + } } } @@ -544,9 +580,11 @@ public final class StatsManager { public void onPullAtom(int atomTag, IPullAtomResultReceiver resultReceiver) { mExecutor.execute(() -> { List data = new ArrayList<>(); - boolean success = mCallback.onPullAtom(atomTag, data); + int successInt = mCallback.onPullAtom(atomTag, data); + boolean success = successInt == PULL_SUCCESS; StatsEventParcel[] parcels = new StatsEventParcel[data.size()]; for (int i = 0; i < data.size(); i++) { + parcels[i] = new StatsEventParcel(); parcels[i].buffer = data.get(i).getBytes(); } try { @@ -649,9 +687,9 @@ public final class StatsManager { public interface StatsPullAtomCallback { /** * Pull data for the specified atom tag, filling in the provided list of StatsEvent data. - * @return if the pull was successful + * @return {@link #PULL_SUCCESS} if the pull was successful, or {@link #PULL_SKIP} if not. */ - boolean onPullAtom(int atomTag, List data); + int onPullAtom(int atomTag, List data); } private class StatsdDeathRecipient implements IBinder.DeathRecipient {