diff options
| author | 2019-01-18 10:09:33 -0800 | |
|---|---|---|
| committer | 2019-02-13 10:47:27 -0800 | |
| commit | 6b1667c8b1c8bdbe9d59b1ed99de46e2fed2139e (patch) | |
| tree | b4ef50aca7b349766b7cb4710b9905afce73b556 | |
| parent | e34c699d84fcf4cb764536994de229a3190100af (diff) | |
add api to log BinaryPushStateChanged atom
This api is to log BinaryPushStateChanged.
Experiment id is added as a binary blob that is not expected to be
accessed on device side.
This cl is mainly for API.
Will add follow up cls for persisting train info on disk and make puller
for it.
Will address sepolicy in follow up cls.
Bug: 119633962
Bug: 119685453
Test: will add gts
Change-Id: I68b4246cf7e8079155e16121ca37a312b35a5328
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | cmds/statsd/Android.bp | 1 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsService.cpp | 57 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsService.h | 8 | ||||
| -rw-r--r-- | cmds/statsd/src/atoms.proto | 20 | ||||
| -rw-r--r-- | cmds/statsd/src/logd/LogEvent.cpp | 21 | ||||
| -rw-r--r-- | cmds/statsd/src/logd/LogEvent.h | 5 | ||||
| -rw-r--r-- | cmds/statsd/src/storage/StorageManager.cpp | 68 | ||||
| -rw-r--r-- | cmds/statsd/src/storage/StorageManager.h | 17 | ||||
| -rw-r--r-- | cmds/statsd/statsd.rc | 1 | ||||
| -rw-r--r-- | cmds/statsd/tests/storage/StorageManager_test.cpp | 52 | ||||
| -rw-r--r-- | core/java/android/os/IStatsManager.aidl | 21 | ||||
| -rw-r--r-- | core/java/android/util/StatsLog.java | 95 |
13 files changed, 349 insertions, 18 deletions
diff --git a/api/current.txt b/api/current.txt index c5cd57378a9d..69d1956c1690 100644 --- a/api/current.txt +++ b/api/current.txt @@ -48985,6 +48985,7 @@ package android.util { } public final class StatsLog { + method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public static boolean logBinaryPushStateChanged(@NonNull String, long, int, int, @NonNull long[]); method public static boolean logEvent(int); method public static boolean logStart(int); method public static boolean logStop(int); diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index faf2053835fa..04ab59218af2 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -238,6 +238,7 @@ cc_test { "tests/guardrail/StatsdStats_test.cpp", "tests/metrics/metrics_test_helper.cpp", "tests/statsd_test_util.cpp", + "tests/storage/StorageManager_test.cpp", "tests/e2e/WakelockDuration_e2e_test.cpp", "tests/e2e/MetricActivation_e2e_test.cpp", "tests/e2e/MetricConditionLink_e2e_test.cpp", diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index bd21a955729d..92d879a2a3c3 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -31,6 +31,7 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/PermissionController.h> +#include <cutils/multiuser.h> #include <dirent.h> #include <frameworks/base/cmds/statsd/src/statsd_config.pb.h> #include <private/android_filesystem_config.h> @@ -47,12 +48,16 @@ using namespace android; using android::base::StringPrintf; using android::util::FIELD_COUNT_REPEATED; +using android::util::FIELD_TYPE_INT64; using android::util::FIELD_TYPE_MESSAGE; namespace android { namespace os { namespace statsd { +const int FIELD_ID_EXPERIMENT_ID = 1; +const int FIELD_ID_EXPERIMENT_ID_MSG = 7; + constexpr const char* kPermissionDump = "android.permission.DUMP"; constexpr const char* kPermissionUsage = "android.permission.PACKAGE_USAGE_STATS"; @@ -1075,6 +1080,58 @@ Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& p return Status::ok(); } +Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& trainName, + int64_t trainVersionCode, int options, + int32_t state, + const std::vector<int64_t>& experimentIds) { + uid_t uid = IPCThreadState::self()->getCallingUid(); + // For testing + if (uid == AID_ROOT || uid == AID_SYSTEM || uid == AID_SHELL) { + return ok(); + } + + // Caller must be granted these permissions + if (!checkCallingPermission(String16(kPermissionDump))) { + return exception(binder::Status::EX_SECURITY, + StringPrintf("UID %d lacks permission %s", uid, kPermissionDump)); + } + if (!checkCallingPermission(String16(kPermissionUsage))) { + return exception(binder::Status::EX_SECURITY, + StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage)); + } + // TODO: add verifier permission + + userid_t userId = multiuser_get_user_id(uid); + + bool requiresStaging = options | IStatsManager::FLAG_REQUIRE_STAGING; + bool rollbackEnabled = options | IStatsManager::FLAG_ROLLBACK_ENABLED; + bool requiresLowLatencyMonitor = options | IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR; + + ProtoOutputStream proto; + uint64_t protoToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_EXPERIMENT_ID_MSG); + for (const auto& expId : experimentIds) { + proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID, + (long long)expId); + } + proto.end(protoToken); + + vector<uint8_t> buffer; + buffer.resize(proto.size()); + size_t pos = 0; + auto iter = proto.data(); + while (iter.readBuffer() != NULL) { + size_t toRead = iter.currentToRead(); + std::memcpy(&(buffer[pos]), iter.readBuffer(), toRead); + pos += toRead; + iter.rp()->move(toRead); + } + LogEvent event(std::string(String8(trainName).string()), trainVersionCode, requiresStaging, + rollbackEnabled, requiresLowLatencyMonitor, state, buffer, userId); + mProcessor->OnLogEvent(&event); + StorageManager::writeTrainInfo(trainVersionCode, buffer); + return Status::ok(); +} + hardware::Return<void> StatsService::reportSpeakerImpedance( const SpeakerImpedance& speakerImpedance) { LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), speakerImpedance); diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 941ed462b303..0a1a314966dd 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -31,6 +31,7 @@ #include <android/frameworks/stats/1.0/types.h> #include <android/os/BnStatsManager.h> #include <android/os/IStatsCompanionService.h> +#include <android/os/IStatsManager.h> #include <binder/IResultReceiver.h> #include <utils/Looper.h> @@ -186,6 +187,13 @@ public: virtual Status unregisterPullerCallback(int32_t atomTag, const String16& packageName) override; /** + * Binder call to log BinaryPushStateChanged atom. + */ + virtual Status sendBinaryPushStateChangedAtom( + const android::String16& trainName, int64_t trainVersionCode, int options, + int32_t state, const std::vector<int64_t>& experimentIds) override; + + /** * Binder call to get SpeakerImpedance atom. */ virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override; diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index da7e4daaf22b..1d764e325955 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -3152,6 +3152,13 @@ message FlagFlipUpdateOccurred { optional int64 order_id = 2; } +/** + * Potential experiment ids that goes with a train install. + */ +message TrainExperimentIds { + repeated int64 experiment_id = 1; +} + /* * Logs when a binary push state changes. * Logged by the installer via public api. @@ -3178,8 +3185,14 @@ message BinaryPushStateChanged { INSTALL_FAILURE = 6; INSTALL_CANCELLED = 7; INSTALLER_ROLLBACK_REQUESTED = 8; + INSTALLER_ROLLBACK_SUCCESS = 9; + INSTALLER_ROLLBACK_FAILURE = 10; } optional State state = 6; + // Possible experiment ids for monitoring this push. + optional TrainExperimentIds experiment_ids = 7 [(log_mode) = MODE_BYTES]; + // user id + optional int32 user_id = 8; } /** Represents USB port overheat event. */ @@ -5507,13 +5520,6 @@ message DeviceIdentifierAccessDenied { } /** - * Potential experiment ids that goes with a train install. - */ -message TrainExperimentIds { - repeated int64 experiment_id = 1; -} - -/** * Pulls the ongoing mainline install train version code. * Pulled from StatsCompanionService */ diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 40a4070d2974..99ebc965f5a8 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -20,6 +20,8 @@ #include "stats_log_util.h" #include "statslog.h" +#include <binder/IPCThreadState.h> + namespace android { namespace os { namespace statsd { @@ -180,6 +182,25 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT } } +LogEvent::LogEvent(const string& trainName, int64_t trainVersionCode, bool requiresStaging, + bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state, + const std::vector<uint8_t>& experimentIds, int32_t userId) { + mLogdTimestampNs = getWallClockNs(); + mElapsedTimestampNs = getElapsedRealtimeNs(); + mTagId = android::util::BINARY_PUSH_STATE_CHANGED; + mLogUid = android::IPCThreadState::self()->getCallingUid(); + + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), Value(trainName))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainVersionCode))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value((int)requiresStaging))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value((int)rollbackEnabled))); + mValues.push_back( + FieldValue(Field(mTagId, getSimpleField(5)), Value((int)requiresLowLatencyMonitor))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(6)), Value(state))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(7)), Value(experimentIds))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(8)), Value(userId))); +} + LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, const SpeakerImpedance& speakerImpedance) { mLogdTimestampNs = wallClockTimestampNs; diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 784376a1580c..6b5fa56d4c8b 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -97,6 +97,11 @@ public: const std::map<int32_t, std::string>& string_map, const std::map<int32_t, float>& float_map); + // Constructs a BinaryPushStateChanged LogEvent from API call. + explicit LogEvent(const std::string& trainName, int64_t trainVersionCode, bool requiresStaging, + bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state, + const std::vector<uint8_t>& experimentIds, int32_t userId); + explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, const SpeakerImpedance& speakerImpedance); diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp index 90f641a34b85..fe465cefd0f4 100644 --- a/cmds/statsd/src/storage/StorageManager.cpp +++ b/cmds/statsd/src/storage/StorageManager.cpp @@ -38,10 +38,13 @@ using std::map; #define STATS_DATA_DIR "/data/misc/stats-data" #define STATS_SERVICE_DIR "/data/misc/stats-service" +#define TRAIN_INFO_DIR "/data/misc/train-info" // for ConfigMetricsReportList const int FIELD_ID_REPORTS = 2; +std::mutex StorageManager::sTrainInfoMutex; + using android::base::StringPrintf; using std::unique_ptr; @@ -92,6 +95,71 @@ void StorageManager::writeFile(const char* file, const void* buffer, int numByte close(fd); } +bool StorageManager::writeTrainInfo(int64_t trainVersionCode, + const std::vector<uint8_t>& experimentIds) { + std::lock_guard<std::mutex> lock(sTrainInfoMutex); + + deleteAllFiles(TRAIN_INFO_DIR); + + string file_name = StringPrintf("%s/%lld", TRAIN_INFO_DIR, (long long)trainVersionCode); + + int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); + if (fd == -1) { + VLOG("Attempt to access %s but failed", file_name.c_str()); + return false; + } + + size_t result = write(fd, experimentIds.data(), experimentIds.size()); + if (result == experimentIds.size()) { + VLOG("Successfully wrote %s", file_name.c_str()); + } else { + VLOG("Failed to write %s", file_name.c_str()); + return false; + } + + result = fchown(fd, AID_STATSD, AID_STATSD); + if (result) { + VLOG("Failed to chown %s to statsd", file_name.c_str()); + return false; + } + + close(fd); + return true; +} + +bool StorageManager::readTrainInfo(TrainInfo& trainInfo) { + std::lock_guard<std::mutex> lock(sTrainInfoMutex); + + unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir); + + if (dir == NULL) { + VLOG("Directory does not exist: %s", TRAIN_INFO_DIR); + return false; + } + + dirent* de; + while ((de = readdir(dir.get()))) { + char* name = de->d_name; + if (name[0] == '.') { + continue; + } + trainInfo.trainVersionCode = StrToInt64(name); + string fullPath = StringPrintf("%s/%s", TRAIN_INFO_DIR, name); + int fd = open(fullPath.c_str(), O_RDONLY | O_CLOEXEC); + if (fd != -1) { + string str; + if (android::base::ReadFdToString(fd, &str)) { + close(fd); + std::copy(str.begin(), str.end(), std::back_inserter(trainInfo.experimentIds)); + VLOG("Read train info file successful: %s", fullPath.c_str()); + return true; + } + } + close(fd); + } + return false; +} + void StorageManager::deleteFile(const char* file) { if (remove(file) != 0) { VLOG("Attempt to delete %s but is not found", file); diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h index dcf3bb607380..d9eca9f5cdc2 100644 --- a/cmds/statsd/src/storage/StorageManager.h +++ b/cmds/statsd/src/storage/StorageManager.h @@ -29,6 +29,11 @@ namespace statsd { using android::util::ProtoOutputStream; +struct TrainInfo { + int64_t trainVersionCode; + std::vector<uint8_t> experimentIds; +}; + class StorageManager : public virtual RefBase { public: /** @@ -37,6 +42,16 @@ public: static void writeFile(const char* file, const void* buffer, int numBytes); /** + * Writes train info. + */ + static bool writeTrainInfo(int64_t trainVersionCode, const std::vector<uint8_t>& experimentIds); + + /** + * Reads train info. + */ + static bool readTrainInfo(TrainInfo& trainInfo); + + /** * Reads the file content to the buffer. */ static bool readFileToString(const char* file, string* content); @@ -109,6 +124,8 @@ private: * Prints disk usage statistics about a directory related to statsd. */ static void printDirStats(int out, const char* path); + + static std::mutex sTrainInfoMutex; }; } // namespace statsd diff --git a/cmds/statsd/statsd.rc b/cmds/statsd/statsd.rc index e0cbd5d25716..a98ecd586b42 100644 --- a/cmds/statsd/statsd.rc +++ b/cmds/statsd/statsd.rc @@ -27,3 +27,4 @@ on post-fs-data mkdir /data/misc/stats-data/ 0770 statsd system mkdir /data/misc/stats-service/ 0770 statsd system mkdir /data/misc/stats-active-metric/ 0770 statsd system + mkdir /data/misc/train-info/ 0770 statsd system diff --git a/cmds/statsd/tests/storage/StorageManager_test.cpp b/cmds/statsd/tests/storage/StorageManager_test.cpp new file mode 100644 index 000000000000..ce957a3ec771 --- /dev/null +++ b/cmds/statsd/tests/storage/StorageManager_test.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <stdio.h> +#include "src/storage/StorageManager.h" + +#ifdef __ANDROID__ + +namespace android { +namespace os { +namespace statsd { + +using namespace testing; +using std::make_shared; +using std::shared_ptr; +using std::vector; +using testing::Contains; + +TEST(StorageManagerTest, TrainInfoReadWriteTest) { + TrainInfo trainInfo; + trainInfo.trainVersionCode = 12345; + const char* expIds = "test_ids"; + trainInfo.experimentIds.assign(expIds, expIds + strlen(expIds)); + + StorageManager::writeTrainInfo(trainInfo.trainVersionCode, trainInfo.experimentIds); + + TrainInfo result; + StorageManager::readTrainInfo(result); + EXPECT_EQ(trainInfo.trainVersionCode, result.trainVersionCode); + EXPECT_EQ(trainInfo.experimentIds.size(), result.experimentIds.size()); + EXPECT_EQ(trainInfo.experimentIds, result.experimentIds); +} + +} // namespace statsd +} // namespace os +} // namespace android +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl index f1bba1ab2977..6d4c5a034b54 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/core/java/android/os/IStatsManager.aidl @@ -196,4 +196,25 @@ interface IStatsManager { * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS */ oneway void unregisterPullerCallback(int atomTag, String packageName); + + /** + * The install requires staging. + */ + const int FLAG_REQUIRE_STAGING = 0x01; + + /** + * Rollback is enabled with this install. + */ + const int FLAG_ROLLBACK_ENABLED = 0x02; + + /** + * Requires low latency monitoring. + */ + const int FLAG_REQUIRE_LOW_LATENCY_MONITOR = 0x04; + + /** + * Logs an event for binary push for module updates. + */ + oneway void sendBinaryPushStateChangedAtom(in String trainName, in long trainVersionCode, + in int options, in int state, in long[] experimentId); } diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index ace4bf477af6..29ced3eda4ec 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -16,7 +16,14 @@ package android.util; +import static android.Manifest.permission.DUMP; +import static android.Manifest.permission.PACKAGE_USAGE_STATS; + +import android.Manifest; import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.app.IActivityManager; +import android.content.Context; import android.os.IStatsManager; import android.os.RemoteException; import android.os.ServiceManager; @@ -31,7 +38,10 @@ public final class StatsLog extends StatsLogInternal { private static IStatsManager sService; - private StatsLog() {} + private static Object sLogLock = new Object(); + + private StatsLog() { + } /** * Logs a start event. @@ -40,11 +50,13 @@ public final class StatsLog extends StatsLogInternal { * @return True if the log request was sent to statsd. */ public static boolean logStart(int label) { - synchronized (StatsLog.class) { + synchronized (sLogLock) { try { IStatsManager service = getIStatsManagerLocked(); if (service == null) { - if (DEBUG) Slog.d(TAG, "Failed to find statsd when logging start"); + if (DEBUG) { + Slog.d(TAG, "Failed to find statsd when logging start"); + } return false; } service.sendAppBreadcrumbAtom(label, @@ -52,7 +64,9 @@ public final class StatsLog extends StatsLogInternal { return true; } catch (RemoteException e) { sService = null; - if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when logging start"); + if (DEBUG) { + Slog.d(TAG, "Failed to connect to statsd when logging start"); + } return false; } } @@ -65,18 +79,22 @@ public final class StatsLog extends StatsLogInternal { * @return True if the log request was sent to statsd. */ public static boolean logStop(int label) { - synchronized (StatsLog.class) { + synchronized (sLogLock) { try { IStatsManager service = getIStatsManagerLocked(); if (service == null) { - if (DEBUG) Slog.d(TAG, "Failed to find statsd when logging stop"); + if (DEBUG) { + Slog.d(TAG, "Failed to find statsd when logging stop"); + } return false; } service.sendAppBreadcrumbAtom(label, StatsLog.APP_BREADCRUMB_REPORTED__STATE__STOP); return true; } catch (RemoteException e) { sService = null; - if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when logging stop"); + if (DEBUG) { + Slog.d(TAG, "Failed to connect to statsd when logging stop"); + } return false; } } @@ -89,11 +107,13 @@ public final class StatsLog extends StatsLogInternal { * @return True if the log request was sent to statsd. */ public static boolean logEvent(int label) { - synchronized (StatsLog.class) { + synchronized (sLogLock) { try { IStatsManager service = getIStatsManagerLocked(); if (service == null) { - if (DEBUG) Slog.d(TAG, "Failed to find statsd when logging event"); + if (DEBUG) { + Slog.d(TAG, "Failed to find statsd when logging event"); + } return false; } service.sendAppBreadcrumbAtom( @@ -101,7 +121,51 @@ public final class StatsLog extends StatsLogInternal { return true; } catch (RemoteException e) { sService = null; - if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when logging event"); + if (DEBUG) { + Slog.d(TAG, "Failed to connect to statsd when logging event"); + } + return false; + } + } + } + + /** + * Logs an event for binary push for module updates. + * + * @param trainName name of install train. + * @param trainVersionCode version code of the train. + * @param options optional flags about this install. + * @param state current install state. + * @param experimentIds experiment ids. + * @return True if the log request was sent to statsd. + */ + @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS}) + public static boolean logBinaryPushStateChanged(@NonNull String trainName, + long trainVersionCode, int options, int state, + @NonNull long[] experimentIds) { + synchronized (sLogLock) { + try { + IStatsManager service = getIStatsManagerLocked(); + if (service == null) { + if (DEBUG) { + Slog.d(TAG, "Failed to find statsd when logging event"); + } + return false; + } + int userId = IActivityManager.Stub.asInterface( + ServiceManager.getService("activity")) + .getCurrentUser() + .id; + service.sendBinaryPushStateChangedAtom( + trainName, trainVersionCode, options, state, experimentIds); + return true; + } catch (RemoteException e) { + sService = null; + if (DEBUG) { + Slog.d(TAG, + "Failed to connect to StatsCompanionService when logging " + + "BinaryPushStateChanged"); + } return false; } } @@ -118,7 +182,7 @@ public final class StatsLog extends StatsLogInternal { /** * Add a log to the stats log. * - * @param id The id of the atom + * @param id The id of the atom * @param params The parameters of the atom's message. */ public static void write(int id, @NonNull Object... params) { @@ -128,4 +192,13 @@ public final class StatsLog extends StatsLogInternal { (boolean) params[4], (int) params[5]); } } + + private static void enforceDumpCallingPermission(Context context) { + context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission."); + } + + private static void enforcesageStatsCallingPermission(Context context) { + context.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS, + "Need PACKAGE_USAGE_STATS permission."); + } } |