Merge "StatsManager throws exceptions" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
6b317915e8
@@ -383,12 +383,18 @@ package android.app {
|
||||
}
|
||||
|
||||
public final class StatsManager {
|
||||
method public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException;
|
||||
method public boolean addConfiguration(long, byte[]);
|
||||
method public byte[] getData(long);
|
||||
method public byte[] getMetadata();
|
||||
method public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException;
|
||||
method public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
|
||||
method public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
|
||||
method public boolean removeConfiguration(long);
|
||||
method public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
|
||||
method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
|
||||
method public boolean setDataFetchOperation(long, android.app.PendingIntent);
|
||||
method public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
|
||||
field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
|
||||
field public static final java.lang.String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
|
||||
field public static final java.lang.String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
|
||||
@@ -398,6 +404,11 @@ package android.app {
|
||||
field public static final java.lang.String EXTRA_STATS_SUBSCRIPTION_RULE_ID = "android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
|
||||
}
|
||||
|
||||
public static class StatsManager.StatsUnavailableException extends android.util.AndroidException {
|
||||
ctor public StatsManager.StatsUnavailableException(java.lang.String);
|
||||
ctor public StatsManager.StatsUnavailableException(java.lang.String, java.lang.Throwable);
|
||||
}
|
||||
|
||||
public class VrManager {
|
||||
method public void setAndBindVrCompositor(android.content.ComponentName);
|
||||
method public void setPersistentVrModeEnabled(boolean);
|
||||
|
||||
@@ -780,8 +780,6 @@ Status StatsService::writeDataToDisk() {
|
||||
}
|
||||
|
||||
void StatsService::sayHiToStatsCompanion() {
|
||||
// TODO: This method needs to be private. It is temporarily public and unsecured for testing
|
||||
// purposes.
|
||||
sp<IStatsCompanionService> statsCompanion = getStatsCompanionService();
|
||||
if (statsCompanion != nullptr) {
|
||||
VLOG("Telling statsCompanion that statsd is ready");
|
||||
@@ -825,42 +823,37 @@ void StatsService::OnLogEvent(LogEvent* event, bool reconnectionStarts) {
|
||||
Status StatsService::getData(int64_t key, vector<uint8_t>* output) {
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
|
||||
if (checkCallingPermission(String16(kPermissionDump))) {
|
||||
ConfigKey configKey(ipc->getCallingUid(), key);
|
||||
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
|
||||
false /* include_current_bucket*/, output);
|
||||
return Status::ok();
|
||||
} else {
|
||||
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) {
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
VLOG("StatsService::getMetadata with Pid %i, Uid %i", ipc->getCallingPid(),
|
||||
ipc->getCallingUid());
|
||||
if (checkCallingPermission(String16(kPermissionDump))) {
|
||||
StatsdStats::getInstance().dumpStats(output, false); // Don't reset the counters.
|
||||
return Status::ok();
|
||||
} else {
|
||||
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,
|
||||
bool* success) {
|
||||
Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config) {
|
||||
if (!checkCallingPermission(String16(kPermissionDump))) {
|
||||
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
|
||||
}
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
if (checkCallingPermission(String16(kPermissionDump))) {
|
||||
if (addConfigurationChecked(ipc->getCallingUid(), key, config)) {
|
||||
*success = true;
|
||||
} else {
|
||||
*success = false;
|
||||
}
|
||||
if (addConfigurationChecked(ipc->getCallingUid(), key, config)) {
|
||||
return Status::ok();
|
||||
} else {
|
||||
*success = false;
|
||||
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
|
||||
ALOGE("Could not parse malformatted StatsdConfig");
|
||||
return Status::fromExceptionCode(binder::Status::EX_ILLEGAL_ARGUMENT,
|
||||
"config does not correspond to a StatsdConfig proto");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -876,80 +869,62 @@ bool StatsService::addConfigurationChecked(int uid, int64_t key, const vector<ui
|
||||
return true;
|
||||
}
|
||||
|
||||
Status StatsService::removeDataFetchOperation(int64_t key, bool* success) {
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
if (checkCallingPermission(String16(kPermissionDump))) {
|
||||
ConfigKey configKey(ipc->getCallingUid(), key);
|
||||
mConfigManager->RemoveConfigReceiver(configKey);
|
||||
*success = true;
|
||||
return Status::ok();
|
||||
} else {
|
||||
*success = false;
|
||||
Status StatsService::removeDataFetchOperation(int64_t key) {
|
||||
if (!checkCallingPermission(String16(kPermissionDump))) {
|
||||
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
|
||||
}
|
||||
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,
|
||||
bool* success) {
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
if (checkCallingPermission(String16(kPermissionDump))) {
|
||||
ConfigKey configKey(ipc->getCallingUid(), key);
|
||||
mConfigManager->SetConfigReceiver(configKey, intentSender);
|
||||
*success = true;
|
||||
return Status::ok();
|
||||
} else {
|
||||
*success = false;
|
||||
Status StatsService::setDataFetchOperation(int64_t key, const sp<android::IBinder>& intentSender) {
|
||||
if (!checkCallingPermission(String16(kPermissionDump))) {
|
||||
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
|
||||
}
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
ConfigKey configKey(ipc->getCallingUid(), key);
|
||||
mConfigManager->SetConfigReceiver(configKey, intentSender);
|
||||
return Status::ok();
|
||||
}
|
||||
|
||||
Status StatsService::removeConfiguration(int64_t key, bool* success) {
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
if (checkCallingPermission(String16(kPermissionDump))) {
|
||||
ConfigKey configKey(ipc->getCallingUid(), key);
|
||||
mConfigManager->RemoveConfig(configKey);
|
||||
SubscriberReporter::getInstance().removeConfig(configKey);
|
||||
*success = true;
|
||||
return Status::ok();
|
||||
} else {
|
||||
*success = false;
|
||||
Status StatsService::removeConfiguration(int64_t key) {
|
||||
if (!checkCallingPermission(String16(kPermissionDump))) {
|
||||
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
|
||||
}
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
ConfigKey configKey(ipc->getCallingUid(), key);
|
||||
mConfigManager->RemoveConfig(configKey);
|
||||
SubscriberReporter::getInstance().removeConfig(configKey);
|
||||
return Status::ok();
|
||||
}
|
||||
|
||||
Status StatsService::setBroadcastSubscriber(int64_t configId,
|
||||
int64_t subscriberId,
|
||||
const sp<android::IBinder>& intentSender,
|
||||
bool* success) {
|
||||
const sp<android::IBinder>& intentSender) {
|
||||
VLOG("StatsService::setBroadcastSubscriber called.");
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
if (checkCallingPermission(String16(kPermissionDump))) {
|
||||
ConfigKey configKey(ipc->getCallingUid(), configId);
|
||||
SubscriberReporter::getInstance()
|
||||
.setBroadcastSubscriber(configKey, subscriberId, intentSender);
|
||||
*success = true;
|
||||
return Status::ok();
|
||||
} else {
|
||||
*success = false;
|
||||
if (!checkCallingPermission(String16(kPermissionDump))) {
|
||||
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
|
||||
}
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
ConfigKey configKey(ipc->getCallingUid(), configId);
|
||||
SubscriberReporter::getInstance()
|
||||
.setBroadcastSubscriber(configKey, subscriberId, intentSender);
|
||||
return Status::ok();
|
||||
}
|
||||
|
||||
Status StatsService::unsetBroadcastSubscriber(int64_t configId,
|
||||
int64_t subscriberId,
|
||||
bool* success) {
|
||||
int64_t subscriberId) {
|
||||
VLOG("StatsService::unsetBroadcastSubscriber called.");
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
if (checkCallingPermission(String16(kPermissionDump))) {
|
||||
ConfigKey configKey(ipc->getCallingUid(), configId);
|
||||
SubscriberReporter::getInstance()
|
||||
.unsetBroadcastSubscriber(configKey, subscriberId);
|
||||
*success = true;
|
||||
return Status::ok();
|
||||
} else {
|
||||
*success = false;
|
||||
if (!checkCallingPermission(String16(kPermissionDump))) {
|
||||
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
|
||||
}
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
ConfigKey configKey(ipc->getCallingUid(), configId);
|
||||
SubscriberReporter::getInstance()
|
||||
.unsetBroadcastSubscriber(configKey, subscriberId);
|
||||
return Status::ok();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -94,24 +94,23 @@ public:
|
||||
* 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,
|
||||
bool* success) override;
|
||||
virtual Status addConfiguration(int64_t key, const vector<uint8_t>& config) 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,
|
||||
bool* success) override;
|
||||
virtual Status setDataFetchOperation(int64_t key,
|
||||
const sp<android::IBinder>& intentSender) override;
|
||||
|
||||
/**
|
||||
* Binder call to remove the data fetch operation for the specified config key.
|
||||
*/
|
||||
virtual Status removeDataFetchOperation(int64_t key, bool* success) override;
|
||||
virtual Status removeDataFetchOperation(int64_t key) override;
|
||||
|
||||
/**
|
||||
* Binder call to allow clients to remove the specified configuration.
|
||||
*/
|
||||
virtual Status removeConfiguration(int64_t key, bool* success) override;
|
||||
virtual Status removeConfiguration(int64_t key) override;
|
||||
|
||||
/**
|
||||
* Binder call to associate the given config's subscriberId with the given intentSender.
|
||||
@@ -119,17 +118,13 @@ public:
|
||||
*/
|
||||
virtual Status setBroadcastSubscriber(int64_t configId,
|
||||
int64_t subscriberId,
|
||||
const sp<android::IBinder>& intentSender,
|
||||
bool* success) override;
|
||||
const sp<android::IBinder>& intentSender) override;
|
||||
|
||||
/**
|
||||
* Binder call to unassociate the given config's subscriberId with any intentSender.
|
||||
*/
|
||||
virtual Status unsetBroadcastSubscriber(int64_t configId, int64_t subscriberId,
|
||||
bool* success) override;
|
||||
virtual Status unsetBroadcastSubscriber(int64_t configId, int64_t subscriberId) override;
|
||||
|
||||
// TODO: public for testing since statsd doesn't run when system starts. Change to private
|
||||
// later.
|
||||
/** Inform statsCompanion that statsd is ready. */
|
||||
virtual void sayHiToStatsCompanion();
|
||||
|
||||
|
||||
@@ -116,11 +116,6 @@ int main(int /*argc*/, char** /*argv*/) {
|
||||
ALOGE("Failed to add service");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: This line is temporary, since statsd doesn't start up automatically (and therefore
|
||||
// the call in StatsService::SystemRunning() won't ever be called right now).
|
||||
// TODO: Are you sure? Don't we need to reconnect to the system process if we get restarted?
|
||||
// --joeo
|
||||
service->sayHiToStatsCompanion();
|
||||
|
||||
// Start the log reader thread
|
||||
|
||||
@@ -35,7 +35,7 @@ void SendConfig(StatsService& service, const StatsdConfig& config) {
|
||||
config.SerializeToString(&str);
|
||||
std::vector<uint8_t> configAsVec(str.begin(), str.end());
|
||||
bool success;
|
||||
service.addConfiguration(kConfigKey, configAsVec, &success);
|
||||
service.addConfiguration(kConfigKey, configAsVec);
|
||||
}
|
||||
|
||||
ConfigMetricsReport GetReports(StatsService& service) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.IntentService;
|
||||
import android.app.StatsManager;
|
||||
import android.app.StatsManager.StatsUnavailableException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
@@ -171,12 +172,16 @@ public class MainActivity extends Activity {
|
||||
return;
|
||||
}
|
||||
if (mStatsManager != null) {
|
||||
byte[] data = mStatsManager.getData(CONFIG_ID);
|
||||
if (data != null) {
|
||||
displayData(data);
|
||||
} else {
|
||||
mReportText.setText("Failed!");
|
||||
try {
|
||||
byte[] data = mStatsManager.getReports(CONFIG_ID);
|
||||
if (data != null) {
|
||||
displayData(data);
|
||||
return;
|
||||
}
|
||||
} catch (StatsUnavailableException e) {
|
||||
Log.e(TAG, "Failed to get data from statsd", e);
|
||||
}
|
||||
mReportText.setText("Failed!");
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -194,10 +199,11 @@ public class MainActivity extends Activity {
|
||||
byte[] config = new byte[inputStream.available()];
|
||||
inputStream.read(config);
|
||||
if (mStatsManager != null) {
|
||||
if (mStatsManager.addConfiguration(CONFIG_ID, config)) {
|
||||
try {
|
||||
mStatsManager.addConfig(CONFIG_ID, config);
|
||||
Toast.makeText(
|
||||
MainActivity.this, "Config pushed", Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
} catch (StatsUnavailableException | IllegalArgumentException e) {
|
||||
Toast.makeText(MainActivity.this, "Config push FAILED!",
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
@@ -218,11 +224,12 @@ public class MainActivity extends Activity {
|
||||
return;
|
||||
}
|
||||
if (mStatsManager != null) {
|
||||
if (mStatsManager.setDataFetchOperation(CONFIG_ID, pi)) {
|
||||
try {
|
||||
mStatsManager.setFetchReportsOperation(pi, CONFIG_ID);
|
||||
Toast.makeText(MainActivity.this,
|
||||
"Receiver specified to pending intent", Toast.LENGTH_LONG)
|
||||
.show();
|
||||
} else {
|
||||
} catch (StatsUnavailableException e) {
|
||||
Toast.makeText(MainActivity.this, "Statsd did not set receiver",
|
||||
Toast.LENGTH_LONG)
|
||||
.show();
|
||||
@@ -241,10 +248,11 @@ public class MainActivity extends Activity {
|
||||
return;
|
||||
}
|
||||
if (mStatsManager != null) {
|
||||
if (mStatsManager.setDataFetchOperation(CONFIG_ID, null)) {
|
||||
try {
|
||||
mStatsManager.setFetchReportsOperation(null, CONFIG_ID);
|
||||
Toast.makeText(MainActivity.this, "Receiver remove", Toast.LENGTH_LONG)
|
||||
.show();
|
||||
} else {
|
||||
} catch (StatsUnavailableException e) {
|
||||
Toast.makeText(MainActivity.this, "Statsd did not remove receiver",
|
||||
Toast.LENGTH_LONG)
|
||||
.show();
|
||||
|
||||
@@ -355,7 +355,13 @@ public class LoadtestActivity extends Activity implements AdapterView.OnItemSele
|
||||
return null;
|
||||
}
|
||||
if (mStatsManager != null) {
|
||||
byte[] data = mStatsManager.getMetadata();
|
||||
byte[] data;
|
||||
try {
|
||||
data = mStatsManager.getStatsMetadata();
|
||||
} catch (StatsManager.StatsUnavailableException e) {
|
||||
Log.e(TAG, "Failed to get data from statsd", e);
|
||||
return null;
|
||||
}
|
||||
if (data != null) {
|
||||
StatsdStatsReport report = null;
|
||||
boolean good = false;
|
||||
@@ -375,7 +381,13 @@ public class LoadtestActivity extends Activity implements AdapterView.OnItemSele
|
||||
return null;
|
||||
}
|
||||
if (mStatsManager != null) {
|
||||
byte[] data = mStatsManager.getData(ConfigFactory.CONFIG_ID);
|
||||
byte[] data;
|
||||
try {
|
||||
data = mStatsManager.getReports(ConfigFactory.CONFIG_ID);
|
||||
} catch (StatsManager.StatsUnavailableException e) {
|
||||
Log.e(TAG, "Failed to get data from statsd", e);
|
||||
return null;
|
||||
}
|
||||
if (data != null) {
|
||||
ConfigMetricsReportList reports = null;
|
||||
try {
|
||||
@@ -563,10 +575,11 @@ public class LoadtestActivity extends Activity implements AdapterView.OnItemSele
|
||||
// TODO: Clear all configs instead of specific ones.
|
||||
if (mStatsManager != null) {
|
||||
if (mStarted) {
|
||||
if (!mStatsManager.removeConfiguration(ConfigFactory.CONFIG_ID)) {
|
||||
try {
|
||||
mStatsManager.removeConfig(ConfigFactory.CONFIG_ID);
|
||||
Log.d(TAG, "Removed loadtest statsd configs.");
|
||||
} else {
|
||||
Log.d(TAG, "Failed to remove loadtest configs.");
|
||||
} catch (StatsManager.StatsUnavailableException e) {
|
||||
Log.e(TAG, "Failed to remove loadtest configs.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -574,12 +587,13 @@ public class LoadtestActivity extends Activity implements AdapterView.OnItemSele
|
||||
|
||||
private boolean setConfig(ConfigFactory.ConfigMetadata configData) {
|
||||
if (mStatsManager != null) {
|
||||
if (mStatsManager.addConfiguration(ConfigFactory.CONFIG_ID, configData.bytes)) {
|
||||
try {
|
||||
mStatsManager.addConfig(ConfigFactory.CONFIG_ID, configData.bytes);
|
||||
mNumMetrics = configData.numMetrics;
|
||||
Log.d(TAG, "Config pushed to statsd");
|
||||
return true;
|
||||
} else {
|
||||
Log.d(TAG, "Failed to push config to statsd");
|
||||
} catch (StatsManager.StatsUnavailableException | IllegalArgumentException e) {
|
||||
Log.e(TAG, "Failed to push config to statsd", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.os.IBinder;
|
||||
import android.os.IStatsManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.AndroidException;
|
||||
import android.util.Slog;
|
||||
|
||||
/**
|
||||
@@ -82,54 +83,73 @@ public final class StatsManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clients can send a configuration and simultaneously registers the name of a broadcast
|
||||
* receiver that listens for when it should request data.
|
||||
* Adds the given configuration and associates it with the given configKey. If a config with the
|
||||
* given configKey already exists for the caller's uid, it is replaced with the new one.
|
||||
*
|
||||
* @param configKey An arbitrary integer that allows clients to track the configuration.
|
||||
* @param config Wire-encoded StatsDConfig proto that specifies metrics (and all
|
||||
* @param config Wire-encoded StatsdConfig proto that specifies metrics (and all
|
||||
* dependencies eg, conditions and matchers).
|
||||
* @return true if successful
|
||||
* @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)
|
||||
public boolean addConfiguration(long configKey, byte[] config) {
|
||||
public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
|
||||
synchronized (this) {
|
||||
try {
|
||||
IStatsManager service = getIStatsManagerLocked();
|
||||
if (service == null) {
|
||||
Slog.e(TAG, "Failed to find statsd when adding configuration");
|
||||
return false;
|
||||
}
|
||||
return service.addConfiguration(configKey, config);
|
||||
service.addConfiguration(configKey, config); // can throw IllegalArgumentException
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to connect to statsd when adding configuration");
|
||||
return false;
|
||||
throw new StatsUnavailableException("could not connect", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Temporary for backwards compatibility. Remove.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.DUMP)
|
||||
public boolean addConfiguration(long configKey, byte[] config) {
|
||||
try {
|
||||
addConfig(configKey, config);
|
||||
return true;
|
||||
} catch (StatsUnavailableException | IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a configuration from logging.
|
||||
*
|
||||
* @param configKey Configuration key to remove.
|
||||
* @return true if successful
|
||||
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.DUMP)
|
||||
public boolean removeConfiguration(long configKey) {
|
||||
public void removeConfig(long configKey) throws StatsUnavailableException {
|
||||
synchronized (this) {
|
||||
try {
|
||||
IStatsManager service = getIStatsManagerLocked();
|
||||
if (service == null) {
|
||||
Slog.e(TAG, "Failed to find statsd when removing configuration");
|
||||
return false;
|
||||
}
|
||||
return service.removeConfiguration(configKey);
|
||||
service.removeConfiguration(configKey);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to connect to statsd when removing configuration");
|
||||
return false;
|
||||
throw new StatsUnavailableException("could not connect", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Temporary for backwards compatibility. Remove.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.DUMP)
|
||||
public boolean removeConfiguration(long configKey) {
|
||||
try {
|
||||
removeConfig(configKey);
|
||||
return true;
|
||||
} catch (StatsUnavailableException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PendingIntent to be used when broadcasting subscriber information to the given
|
||||
* subscriberId within the given config.
|
||||
@@ -150,123 +170,165 @@ public final class StatsManager {
|
||||
* {@link #EXTRA_STATS_DIMENSIONS_VALUE}.
|
||||
* <p>
|
||||
* This function can only be called by the owner (uid) of the config. It must be called each
|
||||
* time statsd starts. The config must have been added first (via addConfiguration()).
|
||||
* time statsd starts. The config must have been added first (via {@link #addConfig}).
|
||||
*
|
||||
* @param configKey The integer naming the config to which this subscriber is attached.
|
||||
* @param subscriberId ID of the subscriber, as used in the config.
|
||||
* @param pendingIntent the PendingIntent to use when broadcasting info to the subscriber
|
||||
* associated with the given subscriberId. May be null, in which case
|
||||
* it undoes any previous setting of this subscriberId.
|
||||
* @return true if successful
|
||||
* @param configKey The integer naming the config to which this subscriber is attached.
|
||||
* @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)
|
||||
public void setBroadcastSubscriber(
|
||||
PendingIntent pendingIntent, long configKey, long subscriberId)
|
||||
throws StatsUnavailableException {
|
||||
synchronized (this) {
|
||||
try {
|
||||
IStatsManager service = getIStatsManagerLocked();
|
||||
if (pendingIntent != null) {
|
||||
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
|
||||
IBinder intentSender = pendingIntent.getTarget().asBinder();
|
||||
service.setBroadcastSubscriber(configKey, subscriberId, intentSender);
|
||||
} else {
|
||||
service.unsetBroadcastSubscriber(configKey, subscriberId);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to connect to statsd when adding broadcast subscriber", e);
|
||||
throw new StatsUnavailableException("could not connect", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Temporary for backwards compatibility. Remove.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.DUMP)
|
||||
public boolean setBroadcastSubscriber(
|
||||
long configKey, long subscriberId, PendingIntent pendingIntent) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
IStatsManager service = getIStatsManagerLocked();
|
||||
if (service == null) {
|
||||
Slog.e(TAG, "Failed to find statsd when adding broadcast subscriber");
|
||||
return false;
|
||||
}
|
||||
if (pendingIntent != null) {
|
||||
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
|
||||
IBinder intentSender = pendingIntent.getTarget().asBinder();
|
||||
return service.setBroadcastSubscriber(configKey, subscriberId, intentSender);
|
||||
} else {
|
||||
return service.unsetBroadcastSubscriber(configKey, subscriberId);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to connect to statsd when adding broadcast subscriber", e);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
setBroadcastSubscriber(pendingIntent, configKey, subscriberId);
|
||||
return true;
|
||||
} catch (StatsUnavailableException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the operation that is called to retrieve the metrics data. This must be called
|
||||
* each time statsd starts. The config must have been added first (via addConfiguration(),
|
||||
* although addConfiguration could have been called on a previous boot). This operation allows
|
||||
* each time statsd starts. The config must have been added first (via {@link #addConfig},
|
||||
* although addConfig could have been called on a previous boot). This operation allows
|
||||
* statsd to send metrics data whenever statsd determines that the metrics in memory are
|
||||
* approaching the memory limits. The fetch operation should call {@link #getData} to fetch the
|
||||
* data, which also deletes the retrieved metrics from statsd's memory.
|
||||
* approaching the memory limits. The fetch operation should call {@link #getReports} to fetch
|
||||
* the data, which also deletes the retrieved metrics from statsd's memory.
|
||||
*
|
||||
* @param configKey The integer naming the config to which this operation is attached.
|
||||
* @param pendingIntent the PendingIntent to use when broadcasting info to the subscriber
|
||||
* associated with the given subscriberId. May be null, in which case
|
||||
* it removes any associated pending intent with this configKey.
|
||||
* @return true if successful
|
||||
* @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)
|
||||
public boolean setDataFetchOperation(long configKey, PendingIntent pendingIntent) {
|
||||
public void setFetchReportsOperation(PendingIntent pendingIntent, long configKey)
|
||||
throws StatsUnavailableException {
|
||||
synchronized (this) {
|
||||
try {
|
||||
IStatsManager service = getIStatsManagerLocked();
|
||||
if (service == null) {
|
||||
Slog.e(TAG, "Failed to find statsd when registering data listener.");
|
||||
return false;
|
||||
}
|
||||
if (pendingIntent == null) {
|
||||
return service.removeDataFetchOperation(configKey);
|
||||
service.removeDataFetchOperation(configKey);
|
||||
} else {
|
||||
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
|
||||
IBinder intentSender = pendingIntent.getTarget().asBinder();
|
||||
return service.setDataFetchOperation(configKey, intentSender);
|
||||
service.setDataFetchOperation(configKey, intentSender);
|
||||
}
|
||||
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to connect to statsd when registering data listener.");
|
||||
return false;
|
||||
throw new StatsUnavailableException("could not connect", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clients can request data with a binder call. This getter is destructive and also clears
|
||||
* the retrieved metrics from statsd memory.
|
||||
*
|
||||
* @param configKey Configuration key to retrieve data from.
|
||||
* @return Serialized ConfigMetricsReportList proto. Returns null on failure (eg, if statsd
|
||||
* crashed).
|
||||
* TODO: Temporary for backwards compatibility. Remove.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.DUMP)
|
||||
public @Nullable byte[] getData(long configKey) {
|
||||
public boolean setDataFetchOperation(long configKey, PendingIntent pendingIntent) {
|
||||
try {
|
||||
setFetchReportsOperation(pendingIntent, configKey);
|
||||
return true;
|
||||
} catch (StatsUnavailableException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the data collected for the given configKey.
|
||||
* This getter is destructive - it also clears the retrieved metrics from statsd's memory.
|
||||
*
|
||||
* @param configKey Configuration key to retrieve data from.
|
||||
* @return Serialized ConfigMetricsReportList proto.
|
||||
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.DUMP)
|
||||
public byte[] getReports(long configKey) throws StatsUnavailableException {
|
||||
synchronized (this) {
|
||||
try {
|
||||
IStatsManager service = getIStatsManagerLocked();
|
||||
if (service == null) {
|
||||
Slog.e(TAG, "Failed to find statsd when getting data");
|
||||
return null;
|
||||
}
|
||||
return service.getData(configKey);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to connect to statsd when getting data");
|
||||
return null;
|
||||
throw new StatsUnavailableException("could not connect", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Temporary for backwards compatibility. Remove.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.DUMP)
|
||||
public @Nullable byte[] getData(long configKey) {
|
||||
try {
|
||||
return getReports(configKey);
|
||||
} catch (StatsUnavailableException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clients can request metadata for statsd. Will contain stats across all configurations but not
|
||||
* the actual metrics themselves (metrics must be collected via {@link #getReports(long)}.
|
||||
* This getter is not destructive and will not reset any metrics/counters.
|
||||
*
|
||||
* @return Serialized StatsdStatsReport proto.
|
||||
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.DUMP)
|
||||
public byte[] getStatsMetadata() throws StatsUnavailableException {
|
||||
synchronized (this) {
|
||||
try {
|
||||
IStatsManager service = getIStatsManagerLocked();
|
||||
return service.getMetadata();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to connect to statsd when getting metadata");
|
||||
throw new StatsUnavailableException("could not connect", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clients can request metadata for statsd. Will contain stats across all configurations but not
|
||||
* the actual metrics themselves (metrics must be collected via {@link #getData(String)}.
|
||||
* the actual metrics themselves (metrics must be collected via {@link #getReports(long)}.
|
||||
* This getter is not destructive and will not reset any metrics/counters.
|
||||
*
|
||||
* @return Serialized StatsdStatsReport proto. Returns null on failure (eg, if statsd crashed).
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.DUMP)
|
||||
public @Nullable byte[] getMetadata() {
|
||||
synchronized (this) {
|
||||
try {
|
||||
IStatsManager service = getIStatsManagerLocked();
|
||||
if (service == null) {
|
||||
Slog.e(TAG, "Failed to find statsd when getting metadata");
|
||||
return null;
|
||||
}
|
||||
return service.getMetadata();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to connect to statsd when getting metadata");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return getStatsMetadata();
|
||||
} catch (StatsUnavailableException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,14 +341,33 @@ public final class StatsManager {
|
||||
}
|
||||
}
|
||||
|
||||
private IStatsManager getIStatsManagerLocked() throws RemoteException {
|
||||
private IStatsManager getIStatsManagerLocked() throws StatsUnavailableException {
|
||||
if (mService != null) {
|
||||
return mService;
|
||||
}
|
||||
mService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
|
||||
if (mService != null) {
|
||||
if (mService == null) {
|
||||
throw new StatsUnavailableException("could not be found");
|
||||
}
|
||||
try {
|
||||
mService.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
|
||||
} catch (RemoteException e) {
|
||||
throw new StatsUnavailableException("could not connect when linkToDeath", e);
|
||||
}
|
||||
return mService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when communication with the stats service fails (eg if it is not available).
|
||||
* This might be thrown early during boot before the stats service has started or if it crashed.
|
||||
*/
|
||||
public static class StatsUnavailableException extends AndroidException {
|
||||
public StatsUnavailableException(String reason) {
|
||||
super("Failed to connect to statsd: " + reason);
|
||||
}
|
||||
|
||||
public StatsUnavailableException(String reason, Throwable e) {
|
||||
super("Failed to connect to statsd: " + reason, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,45 +77,51 @@ interface IStatsManager {
|
||||
/**
|
||||
* Fetches data for the specified configuration key. Returns a byte array representing proto
|
||||
* wire-encoded of ConfigMetricsReportList.
|
||||
*
|
||||
* Requires Manifest.permission.DUMP.
|
||||
*/
|
||||
byte[] getData(in long key);
|
||||
|
||||
/**
|
||||
* Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
|
||||
*
|
||||
* Requires Manifest.permission.DUMP.
|
||||
*/
|
||||
byte[] getMetadata();
|
||||
|
||||
/**
|
||||
* Sets a configuration with the specified config key and subscribes to updates for this
|
||||
* configuration key. Broadcasts will be sent if this configuration needs to be collected.
|
||||
* The configuration must be a wire-encoded StatsDConfig. The receiver for this data is
|
||||
* The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
|
||||
* registered in a separate function.
|
||||
*
|
||||
* Returns if this configuration was correctly registered.
|
||||
* Requires Manifest.permission.DUMP.
|
||||
*/
|
||||
boolean addConfiguration(in long configKey, in byte[] config);
|
||||
void addConfiguration(in long configKey, in byte[] config);
|
||||
|
||||
/**
|
||||
* Registers the given pending intent for this config key. This intent is invoked when the
|
||||
* memory consumed by the metrics for this configuration approach the pre-defined limits. There
|
||||
* can be at most one listener per config key.
|
||||
*
|
||||
* Returns if this listener was correctly registered.
|
||||
* Requires Manifest.permission.DUMP.
|
||||
*/
|
||||
boolean setDataFetchOperation(long configKey, in IBinder intentSender);
|
||||
void setDataFetchOperation(long configKey, in IBinder intentSender);
|
||||
|
||||
/**
|
||||
* Removes the data fetch operation for the specified configuration.
|
||||
*
|
||||
* Requires Manifest.permission.DUMP.
|
||||
*/
|
||||
boolean removeDataFetchOperation(long configKey);
|
||||
void removeDataFetchOperation(long configKey);
|
||||
|
||||
/**
|
||||
* Removes the configuration with the matching config key. No-op if this config key does not
|
||||
* exist.
|
||||
*
|
||||
* Returns if this configuration key was removed.
|
||||
* Requires Manifest.permission.DUMP.
|
||||
*/
|
||||
boolean removeConfiguration(in long configKey);
|
||||
void removeConfiguration(in long configKey);
|
||||
|
||||
/**
|
||||
* Set the IIntentSender (i.e. PendingIntent) to be used when broadcasting subscriber
|
||||
@@ -133,16 +139,16 @@ interface IStatsManager {
|
||||
* intentSender must be convertible into an IntentSender using IntentSender(IBinder)
|
||||
* and cannot be null.
|
||||
*
|
||||
* Returns true if successful.
|
||||
* Requires Manifest.permission.DUMP.
|
||||
*/
|
||||
boolean setBroadcastSubscriber(long configKey, long subscriberId, in IBinder intentSender);
|
||||
void setBroadcastSubscriber(long configKey, long subscriberId, in IBinder intentSender);
|
||||
|
||||
/**
|
||||
* Undoes setBroadcastSubscriber() for the (configKey, subscriberId) pair.
|
||||
* Any broadcasts associated with subscriberId will henceforth not be sent.
|
||||
* No-op if this (configKey, subsriberId) pair was not associated with an IntentSender.
|
||||
*
|
||||
* Returns true if successful.
|
||||
* Requires Manifest.permission.DUMP.
|
||||
*/
|
||||
boolean unsetBroadcastSubscriber(long configKey, long subscriberId);
|
||||
void unsetBroadcastSubscriber(long configKey, long subscriberId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user