#include "subscriber/SubscriberReporter.h"
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/PermissionController.h>
#include <dirent.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <private/android_filesystem_config.h>
using namespace android;
+using android::base::StringPrintf;
+
namespace android {
namespace os {
namespace statsd {
constexpr const char* kPermissionDump = "android.permission.DUMP";
+constexpr const char* kPermissionUsage = "android.permission.PACKAGE_USAGE_STATS";
+
+constexpr const char* kOpUsage = "android:get_usage_stats";
+
#define STATS_SERVICE_DIR "/data/misc/stats-service"
+static binder::Status ok() {
+ return binder::Status::ok();
+}
+
+static binder::Status exception(uint32_t code, const std::string& msg) {
+ ALOGE("%s (%d)", msg.c_str(), code);
+ return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
+}
+
+binder::Status checkUid(uid_t expectedUid) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid == expectedUid || uid == AID_ROOT) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d is not expected UID %d", uid, expectedUid));
+ }
+}
+
+binder::Status checkDumpAndUsageStats(const String16& packageName) {
+ 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) {
+ return ok();
+ }
+
+ // 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));
+ }
+
+ // Caller must also have usage stats op granted
+ PermissionController pc;
+ switch (pc.noteOp(String16(kOpUsage), uid, packageName)) {
+ case PermissionController::MODE_ALLOWED:
+ case PermissionController::MODE_DEFAULT:
+ return ok();
+ default:
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d / PID %d lacks app-op %s", uid, pid, kOpUsage));
+ }
+}
+
+#define ENFORCE_UID(uid) { \
+ binder::Status status = checkUid((uid)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define ENFORCE_DUMP_AND_USAGE_STATS(packageName) { \
+ binder::Status status = checkDumpAndUsageStats(packageName); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
StatsService::StatsService(const sp<Looper>& handlerLooper)
: mAnomalyAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
[](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
* Implementation of the adb shell cmd stats command.
*/
status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
- // TODO: Permission check
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid != AID_ROOT && uid != AID_SHELL) {
+ return PERMISSION_DENIED;
+ }
const int argCount = args.size();
if (argCount >= 1) {
Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version,
const vector<String16>& app) {
- VLOG("StatsService::informAllUidData was called");
-
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call informAllUidData");
- }
+ ENFORCE_UID(AID_SYSTEM);
+ VLOG("StatsService::informAllUidData was called");
mUidMap->updateMap(getElapsedRealtimeNs(), uid, version, app);
VLOG("StatsService::informAllUidData succeeded");
}
Status StatsService::informOnePackage(const String16& app, int32_t uid, int64_t version) {
- VLOG("StatsService::informOnePackage was called");
+ ENFORCE_UID(AID_SYSTEM);
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call informOnePackage");
- }
+ VLOG("StatsService::informOnePackage was called");
mUidMap->updateApp(getElapsedRealtimeNs(), app, uid, version);
return Status::ok();
}
Status StatsService::informOnePackageRemoved(const String16& app, int32_t uid) {
- VLOG("StatsService::informOnePackageRemoved was called");
+ ENFORCE_UID(AID_SYSTEM);
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call informOnePackageRemoved");
- }
+ VLOG("StatsService::informOnePackageRemoved was called");
mUidMap->removeApp(getElapsedRealtimeNs(), app, uid);
mConfigManager->RemoveConfigs(uid);
return Status::ok();
}
Status StatsService::informAnomalyAlarmFired() {
- VLOG("StatsService::informAnomalyAlarmFired was called");
-
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call informAnomalyAlarmFired");
- }
+ ENFORCE_UID(AID_SYSTEM);
+ VLOG("StatsService::informAnomalyAlarmFired was called");
int64_t currentTimeSec = getElapsedRealtimeSec();
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
}
Status StatsService::informAlarmForSubscriberTriggeringFired() {
- VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
-
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(
- Status::EX_SECURITY,
- "Only system uid can call informAlarmForSubscriberTriggeringFired");
- }
+ ENFORCE_UID(AID_SYSTEM);
+ VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
int64_t currentTimeSec = getElapsedRealtimeSec();
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
mPeriodicAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
}
Status StatsService::informPollAlarmFired() {
- VLOG("StatsService::informPollAlarmFired was called");
-
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call informPollAlarmFired");
- }
+ ENFORCE_UID(AID_SYSTEM);
+ VLOG("StatsService::informPollAlarmFired was called");
mProcessor->informPullAlarmFired(getElapsedRealtimeNs());
-
VLOG("StatsService::informPollAlarmFired succeeded");
-
return Status::ok();
}
Status StatsService::systemRunning() {
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call systemRunning");
- }
+ ENFORCE_UID(AID_SYSTEM);
// When system_server is up and running, schedule the dropbox task to run.
VLOG("StatsService::systemRunning");
-
sayHiToStatsCompanion();
-
return Status::ok();
}
Status StatsService::writeDataToDisk() {
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call systemRunning");
- }
+ ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::writeDataToDisk");
-
mProcessor->WriteDataToDisk();
-
return Status::ok();
}
}
Status StatsService::statsCompanionReady() {
- VLOG("StatsService::statsCompanionReady was called");
-
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call statsCompanionReady");
- }
+ ENFORCE_UID(AID_SYSTEM);
+ VLOG("StatsService::statsCompanionReady was called");
sp<IStatsCompanionService> statsCompanion = getStatsCompanionService();
if (statsCompanion == nullptr) {
return Status::fromExceptionCode(
mProcessor->OnLogEvent(event, reconnectionStarts);
}
-Status StatsService::getData(int64_t key, vector<uint8_t>* output) {
+Status StatsService::getData(int64_t key, const String16& packageName, vector<uint8_t>* output) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
ConfigKey configKey(ipc->getCallingUid(), key);
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
false /* include_current_bucket*/, output);
return Status::ok();
}
-Status StatsService::getMetadata(vector<uint8_t>* output) {
+Status StatsService::getMetadata(const String16& packageName, vector<uint8_t>* output) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::getMetadata with Pid %i, Uid %i", ipc->getCallingPid(),
ipc->getCallingUid());
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
StatsdStats::getInstance().dumpStats(output, false); // Don't reset the counters.
return Status::ok();
}
-Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config) {
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
+Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config,
+ const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
if (addConfigurationChecked(ipc->getCallingUid(), key, config)) {
return Status::ok();
return true;
}
-Status StatsService::removeDataFetchOperation(int64_t key) {
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
+Status StatsService::removeDataFetchOperation(int64_t key, const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), key);
mConfigManager->RemoveConfigReceiver(configKey);
return Status::ok();
}
-Status StatsService::setDataFetchOperation(int64_t key, const sp<android::IBinder>& intentSender) {
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
+Status StatsService::setDataFetchOperation(int64_t key,
+ const sp<android::IBinder>& intentSender,
+ const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), key);
mConfigManager->SetConfigReceiver(configKey, intentSender);
return Status::ok();
}
-Status StatsService::removeConfiguration(int64_t key) {
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
+Status StatsService::removeConfiguration(int64_t key, const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), key);
mConfigManager->RemoveConfig(configKey);
Status StatsService::setBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
- const sp<android::IBinder>& intentSender) {
+ const sp<android::IBinder>& intentSender,
+ const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
VLOG("StatsService::setBroadcastSubscriber called.");
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), configId);
SubscriberReporter::getInstance()
}
Status StatsService::unsetBroadcastSubscriber(int64_t configId,
- int64_t subscriberId) {
+ int64_t subscriberId,
+ const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
VLOG("StatsService::unsetBroadcastSubscriber called.");
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), configId);
SubscriberReporter::getInstance()
return Status::ok();
}
-
void StatsService::binderDied(const wp <IBinder>& who) {
ALOGW("statscompanion service died");
mProcessor->WriteDataToDisk();
/**
* Binder call for clients to request data for this configuration key.
*/
- virtual Status getData(int64_t key, vector<uint8_t>* output) override;
+ virtual Status getData(int64_t key,
+ const String16& packageName,
+ vector<uint8_t>* output) override;
/**
* Binder call for clients to get metadata across all configs in statsd.
*/
- virtual Status getMetadata(vector<uint8_t>* output) override;
+ virtual Status getMetadata(const String16& packageName,
+ vector<uint8_t>* output) override;
/**
* Binder call to let clients send a configuration and indicate they're interested when they
* should requestData for this configuration.
*/
- virtual Status addConfiguration(int64_t key, const vector<uint8_t>& config) override;
+ virtual Status addConfiguration(int64_t key,
+ const vector<uint8_t>& config,
+ const String16& packageName) override;
/**
* Binder call to let clients register the data fetch operation for a configuration.
*/
virtual Status setDataFetchOperation(int64_t key,
- const sp<android::IBinder>& intentSender) override;
+ const sp<android::IBinder>& intentSender,
+ const String16& packageName) override;
/**
* Binder call to remove the data fetch operation for the specified config key.
*/
- virtual Status removeDataFetchOperation(int64_t key) override;
+ virtual Status removeDataFetchOperation(int64_t key,
+ const String16& packageName) override;
/**
* Binder call to allow clients to remove the specified configuration.
*/
- virtual Status removeConfiguration(int64_t key) override;
+ virtual Status removeConfiguration(int64_t key,
+ const String16& packageName) override;
/**
* Binder call to associate the given config's subscriberId with the given intentSender.
*/
virtual Status setBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
- const sp<android::IBinder>& intentSender) override;
+ const sp<android::IBinder>& intentSender,
+ const String16& packageName) override;
/**
* Binder call to unassociate the given config's subscriberId with any intentSender.
*/
- virtual Status unsetBroadcastSubscriber(int64_t configId, int64_t subscriberId) override;
+ virtual Status unsetBroadcastSubscriber(int64_t configId,
+ int64_t subscriberId,
+ const String16& packageName) override;
/** Inform statsCompanion that statsd is ready. */
virtual void sayHiToStatsCompanion();
#ifdef __ANDROID__
+const string kAndroid = "android";
const string kApp1 = "app1.sharing.1";
const int kConfigKey = 789130123; // Randomly chosen to avoid collisions with existing configs.
config.SerializeToString(&str);
std::vector<uint8_t> configAsVec(str.begin(), str.end());
bool success;
- service.addConfiguration(kConfigKey, configAsVec);
+ service.addConfiguration(kConfigKey, configAsVec, String16(kAndroid.c_str()));
}
ConfigMetricsReport GetReports(StatsService& service) {
vector<uint8_t> output;
- service.getData(kConfigKey, &output);
+ service.getData(kConfigKey, String16(kAndroid.c_str()), &output);
ConfigMetricsReportList reports;
reports.ParseFromArray(output.data(), output.size());
EXPECT_EQ(1, reports.reports_size());
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
*/
package android.app;
-import android.Manifest;
+import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.PACKAGE_USAGE_STATS;
+
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.content.Context;
import android.os.IBinder;
import android.os.IStatsManager;
import android.os.RemoteException;
*/
@SystemApi
public final class StatsManager {
- IStatsManager mService;
private static final String TAG = "StatsManager";
private static final boolean DEBUG = false;
+ private final Context mContext;
+
+ private IStatsManager mService;
+
/**
* Long extra of uid that added the relevant stats config.
*/
*
* @hide
*/
- public StatsManager() {
+ public StatsManager(Context context) {
+ mContext = context;
}
/**
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
* @throws IllegalArgumentException if config is not a wire-encoded StatsdConfig proto
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
- service.addConfiguration(configKey, config); // can throw IllegalArgumentException
+ // can throw IllegalArgumentException
+ service.addConfiguration(configKey, config, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when adding configuration");
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
/**
* TODO: Temporary for backwards compatibility. Remove.
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean addConfiguration(long configKey, byte[] config) {
try {
addConfig(configKey, config);
* @param configKey Configuration key to remove.
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void removeConfig(long configKey) throws StatsUnavailableException {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
- service.removeConfiguration(configKey);
+ service.removeConfiguration(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when removing configuration");
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
/**
* TODO: Temporary for backwards compatibility. Remove.
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean removeConfiguration(long configKey) {
try {
removeConfig(configKey);
* @param subscriberId ID of the subscriber, as used in the config.
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void setBroadcastSubscriber(
PendingIntent pendingIntent, long configKey, long subscriberId)
throws StatsUnavailableException {
if (pendingIntent != null) {
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
IBinder intentSender = pendingIntent.getTarget().asBinder();
- service.setBroadcastSubscriber(configKey, subscriberId, intentSender);
+ service.setBroadcastSubscriber(configKey, subscriberId, intentSender,
+ mContext.getOpPackageName());
} else {
- service.unsetBroadcastSubscriber(configKey, subscriberId);
+ service.unsetBroadcastSubscriber(configKey, subscriberId,
+ mContext.getOpPackageName());
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when adding broadcast subscriber", e);
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
/**
* TODO: Temporary for backwards compatibility. Remove.
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean setBroadcastSubscriber(
long configKey, long subscriberId, PendingIntent pendingIntent) {
try {
* @param configKey The integer naming the config to which this operation is attached.
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void setFetchReportsOperation(PendingIntent pendingIntent, long configKey)
throws StatsUnavailableException {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
if (pendingIntent == null) {
- service.removeDataFetchOperation(configKey);
+ service.removeDataFetchOperation(configKey, mContext.getOpPackageName());
} else {
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
IBinder intentSender = pendingIntent.getTarget().asBinder();
- service.setDataFetchOperation(configKey, intentSender);
+ service.setDataFetchOperation(configKey, intentSender,
+ mContext.getOpPackageName());
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when registering data listener.");
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
/**
* TODO: Temporary for backwards compatibility. Remove.
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean setDataFetchOperation(long configKey, PendingIntent pendingIntent) {
try {
setFetchReportsOperation(pendingIntent, configKey);
* @return Serialized ConfigMetricsReportList proto.
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public byte[] getReports(long configKey) throws StatsUnavailableException {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
- return service.getData(configKey);
+ return service.getData(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when getting data");
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
/**
* TODO: Temporary for backwards compatibility. Remove.
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public @Nullable byte[] getData(long configKey) {
try {
return getReports(configKey);
* @return Serialized StatsdStatsReport proto.
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public byte[] getStatsMetadata() throws StatsUnavailableException {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
- return service.getMetadata();
+ return service.getMetadata(mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when getting metadata");
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
*
* @return Serialized StatsdStatsReport proto. Returns null on failure (eg, if statsd crashed).
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public @Nullable byte[] getMetadata() {
try {
return getStatsMetadata();
}});
registerService(Context.STATS_MANAGER, StatsManager.class,
- new StaticServiceFetcher<StatsManager>() {
- @Override
- public StatsManager createService() throws ServiceNotFoundException {
- return new StatsManager();
- }});
+ new CachedServiceFetcher<StatsManager>() {
+ @Override
+ public StatsManager createService(ContextImpl ctx) {
+ return new StatsManager(ctx.getOuterContext());
+ }});
registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
new CachedServiceFetcher<StatusBarManager>() {
/** @hide */
interface IPermissionController {
boolean checkPermission(String permission, int pid, int uid);
+ int noteOp(String op, int uid, String packageName);
String[] getPackagesForUid(int uid);
boolean isRuntimePermission(String permission);
int getPackageUid(String packageName, int flags);
*
* Requires Manifest.permission.DUMP.
*/
- byte[] getData(in long key);
+ byte[] getData(in long key, in String packageName);
/**
* Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
*
* Requires Manifest.permission.DUMP.
*/
- byte[] getMetadata();
+ byte[] getMetadata(in String packageName);
/**
* Sets a configuration with the specified config key and subscribes to updates for this
*
* Requires Manifest.permission.DUMP.
*/
- void addConfiguration(in long configKey, in byte[] config);
+ void addConfiguration(in long configKey, in byte[] config, in String packageName);
/**
* Registers the given pending intent for this config key. This intent is invoked when the
*
* Requires Manifest.permission.DUMP.
*/
- void setDataFetchOperation(long configKey, in IBinder intentSender);
+ void setDataFetchOperation(long configKey, in IBinder intentSender, in String packageName);
/**
* Removes the data fetch operation for the specified configuration.
*
* Requires Manifest.permission.DUMP.
*/
- void removeDataFetchOperation(long configKey);
+ void removeDataFetchOperation(long configKey, in String packageName);
/**
* Removes the configuration with the matching config key. No-op if this config key does not
*
* Requires Manifest.permission.DUMP.
*/
- void removeConfiguration(in long configKey);
+ void removeConfiguration(in long configKey, in String packageName);
/**
* Set the IIntentSender (i.e. PendingIntent) to be used when broadcasting subscriber
*
* Requires Manifest.permission.DUMP.
*/
- void setBroadcastSubscriber(long configKey, long subscriberId, in IBinder intentSender);
+ void setBroadcastSubscriber(long configKey, long subscriberId, in IBinder intentSender,
+ in String packageName);
/**
* Undoes setBroadcastSubscriber() for the (configKey, subscriberId) pair.
*
* Requires Manifest.permission.DUMP.
*/
- void unsetBroadcastSubscriber(long configKey, long subscriberId);
+ void unsetBroadcastSubscriber(long configKey, long subscriberId, in String packageName);
}
<assign-permission name="android.permission.DUMP" uid="statsd" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="statsd" />
<assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
+ <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="statsd" />
<!-- This is a list of all the libraries available for application
code to link against. -->
}
@Override
+ public int noteOp(String op, int uid, String packageName) {
+ return mActivityManagerService.mAppOpsService
+ .noteOperation(AppOpsManager.strOpToOp(op), uid, packageName);
+ }
+
+ @Override
public String[] getPackagesForUid(int uid) {
return mActivityManagerService.mContext.getPackageManager()
.getPackagesForUid(uid);
import com.android.internal.os.BinderInternal;
+import android.app.AppOpsManager;
import android.os.Binder;
import android.os.IPermissionController;
import android.os.RemoteException;
public void testSetPermissionController() {
try {
IPermissionController pc = new IPermissionController.Stub() {
+ @Override
public boolean checkPermission(java.lang.String permission, int pid, int uid) {
return true;
}
@Override
+ public int noteOp(String op, int uid, String packageName) {
+ return AppOpsManager.MODE_ALLOWED;
+ }
+
+ @Override
public String[] getPackagesForUid(int uid) {
return new String[0];
}