Merge "CTS for ForegroundServiceAccessAppOpOccurred atom" into rvc-dev
diff --git a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
index 9c55177..7458be5 100644
--- a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
+++ b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
@@ -22,7 +22,10 @@
import android.accounts.Account;
import android.accounts.AccountManager;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningServiceInfo;
import android.app.AlarmManager;
+import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
@@ -61,6 +64,8 @@
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
import org.junit.Test;
import java.util.Arrays;
@@ -71,6 +76,8 @@
public class AtomTests {
private static final String TAG = AtomTests.class.getSimpleName();
+ private static final String MY_PACKAGE_NAME = "com.android.server.cts.device.statsd";
+
@Test
public void testAudioState() {
// TODO: This should surely be getTargetContext(), here and everywhere, but test first.
@@ -230,6 +237,58 @@
}
@Test
+ public void testForegroundServiceAccessAppOp() throws Exception {
+ Context context = InstrumentationRegistry.getContext();
+ Intent fgsIntent = new Intent(context, StatsdCtsForegroundService.class);
+ AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+
+ // No foreground service session
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_COARSE_LOCATION, true);
+
+ // Foreground service session 1
+ context.startService(fgsIntent);
+ while (!checkIfServiceRunning(context, StatsdCtsForegroundService.class.getName())) {
+ sleep(50);
+ }
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA, true);
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_FINE_LOCATION, true);
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA, true);
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_RECORD_AUDIO, false);
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_RECORD_AUDIO, true);
+ context.stopService(fgsIntent);
+
+ // No foreground service session
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_COARSE_LOCATION, true);
+
+ // TODO(b/149098800): Start fgs a second time and log OPSTR_CAMERA again
+ }
+
+ /** @param doNote true if should use noteOp; false if should use startOp. */
+ private void noteAppOp(AppOpsManager appOpsManager, String opStr, boolean doNote) {
+ if (doNote) {
+ ShellIdentityUtils.invokeMethodWithShellPermissions(appOpsManager,
+ (aom) -> aom.noteOp(opStr, android.os.Process.myUid(), MY_PACKAGE_NAME, null,
+ "statsdTest"));
+ } else {
+ ShellIdentityUtils.invokeMethodWithShellPermissions(appOpsManager,
+ (aom) -> aom.startOp(opStr, android.os.Process.myUid(),
+ MY_PACKAGE_NAME, null, "statsdTest"));
+ }
+ sleep(500);
+ }
+
+ /** Check if service is running. */
+ public boolean checkIfServiceRunning(Context context, String serviceName) {
+ ActivityManager manager = context.getSystemService(ActivityManager.class);
+ for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
+ if (serviceName.equals(service.service.getClassName()) && service.foreground) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Test
public void testGpsScan() {
Context context = InstrumentationRegistry.getContext();
final LocationManager locManager = context.getSystemService(LocationManager.class);
@@ -396,7 +455,7 @@
@Test
public void testScheduledJob() throws Exception {
- final ComponentName name = new ComponentName("com.android.server.cts.device.statsd",
+ final ComponentName name = new ComponentName(MY_PACKAGE_NAME,
StatsdJobService.class.getName());
Context context = InstrumentationRegistry.getContext();
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 1d4b2d6..ac45c06 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -22,7 +22,6 @@
import android.os.WakeLockLevelEnum;
import android.server.ErrorSource;
-import com.android.internal.os.StatsdConfigProto.FieldMatcher;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
import com.android.os.AtomsProto;
import com.android.os.AtomsProto.ANROccurred;
@@ -40,12 +39,13 @@
import com.android.os.AtomsProto.DangerousPermissionStateSampled;
import com.android.os.AtomsProto.DeviceCalculatedPowerBlameUid;
import com.android.os.AtomsProto.FlashlightStateChanged;
+import com.android.os.AtomsProto.ForegroundServiceAppOpSessionEnded;
import com.android.os.AtomsProto.ForegroundServiceStateChanged;
import com.android.os.AtomsProto.GpsScanStateChanged;
import com.android.os.AtomsProto.HiddenApiUsed;
import com.android.os.AtomsProto.IonHeapSize;
-import com.android.os.AtomsProto.LooperStats;
import com.android.os.AtomsProto.LmkKillOccurred;
+import com.android.os.AtomsProto.LooperStats;
import com.android.os.AtomsProto.MediaCodecStateChanged;
import com.android.os.AtomsProto.OverlayStateChanged;
import com.android.os.AtomsProto.PackageNotificationPreferences;
@@ -73,7 +73,6 @@
import java.lang.ProcessBuilder;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -544,6 +543,51 @@
atom -> atom.getForegroundServiceStateChanged().getState().getNumber());
}
+
+ public void testForegroundServiceAccessAppOp() throws Exception {
+ if (statsdDisabled()) {
+ return;
+ }
+ final int atomTag = Atom.FOREGROUND_SERVICE_APP_OP_SESSION_ENDED_FIELD_NUMBER;
+ final String name = "testForegroundServiceAccessAppOp";
+
+ createAndUploadConfig(atomTag, false);
+ Thread.sleep(WAIT_TIME_SHORT);
+
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name);
+
+ // Sorted list of events in order in which they occurred.
+ List<EventMetricData> data = getEventMetricDataList();
+
+ assertWithMessage("Wrong atom size").that(data.size()).isEqualTo(3);
+ for (int i = 0; i < data.size(); i++) {
+ ForegroundServiceAppOpSessionEnded atom
+ = data.get(i).getAtom().getForegroundServiceAppOpSessionEnded();
+ final int opName = atom.getAppOpName().getNumber();
+ final int acceptances = atom.getCountOpsAccepted();
+ final int rejections = atom.getCountOpsRejected();
+ final int count = acceptances + rejections;
+ int expectedCount = 0;
+ switch (opName) {
+ case ForegroundServiceAppOpSessionEnded.AppOpName.OP_CAMERA_VALUE:
+ expectedCount = 2;
+ break;
+ case ForegroundServiceAppOpSessionEnded.AppOpName.OP_FINE_LOCATION_VALUE:
+ expectedCount = 1;
+ break;
+ case ForegroundServiceAppOpSessionEnded.AppOpName.OP_RECORD_AUDIO_VALUE:
+ expectedCount = 2;
+ break;
+ case ForegroundServiceAppOpSessionEnded.AppOpName.OP_COARSE_LOCATION_VALUE:
+ // fall-through
+ default:
+ fail("Unexpected opName " + opName);
+ }
+ assertWithMessage("Wrong count for " + opName).that(count).isEqualTo(expectedCount);
+
+ }
+ }
+
public void testGpsScan() throws Exception {
if (statsdDisabled()) {
return;