blob: 96e11722e18073304a758e4931bb1d11affad9bf [file] [log] [blame]
/*
* 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
*/
package com.android.hiddenapiapp;
import android.app.StatsManager;
import android.app.StatsManager.StatsUnavailableException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.DeviceConfig;
import android.util.Log;
import java.util.Base64;
public class Receiver extends BroadcastReceiver {
public static final String SET_RATE = "com.android.hiddenapiapp.SET_RATE";
public static final String SET_CONFIG = "com.android.hiddenapiapp.SET_CONFIG";
public static final String GET_DATA = "com.android.hiddenapiapp.GET_DATA";
public static final String REMOVE_CONFIG = "com.android.hiddenapiapp.REMOVE_CONFIG";
// ID of the config to be sent to statsd; this is an arbitrary value - but, obviously,
// every config must have its own id (can be assigned either client or server side,
// depending on use case)
private static final long CONFIG_ID = 54321;
private static final String TAG = "HiddenApiLogging";
@Override
public void onReceive(Context context, Intent intent) {
StatsManager statsManager = (StatsManager) context.getSystemService(StatsManager.class);
switch (intent.getAction()) {
case SET_RATE:
setLogRate(intent.getIntExtra("rate", 0));
setResult(1, null, null);
break;
case SET_CONFIG:
String config = intent.getStringExtra("config");
if (setupConfig(Base64.getDecoder().decode(config), statsManager)) {
setResult(1, null, null);
} else {
setResult(2, null, null);
}
case GET_DATA:
// This is for demo purposes only; in real applications, this data would be accumulated
// periodically in a buffer, and sent when the buffer fills up or otherwise convenient
setResult(1, Base64.getEncoder().encodeToString(getData(statsManager)), null);
break;
case REMOVE_CONFIG:
if (removeConfig(statsManager)) {
setResult(1, null, null);
} else {
setResult(2, null, null);
}
default:
setResult(2, null, null);
}
}
private void setLogRate(int rate) {
DeviceConfig.setProperty(
"app_compat",
"hidden_api_access_statslog_sampling_rate",
new Integer(rate).toString(),
false);
}
private boolean setupConfig(byte[] config, StatsManager statsManager) {
if (statsManager == null) {
return false;
}
try {
statsManager.addConfig(CONFIG_ID, config);
return true;
} catch (StatsUnavailableException e) {
Log.d(TAG, "Failed to send config to statsd");
return false;
}
}
private byte[] getData(StatsManager statsManager) {
if (statsManager == null) {
return null;
}
try {
return statsManager.getReports(CONFIG_ID);
} catch (StatsUnavailableException e) {
return null;
}
}
private boolean removeConfig(StatsManager statsManager) {
if (statsManager == null) {
return false;
}
try {
statsManager.removeConfig(CONFIG_ID);
statsManager = null;
return true;
} catch (StatsUnavailableException e) {
Log.d(TAG, "Failed to remove config from statsd");
return false;
}
}
}