summaryrefslogtreecommitdiff
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/bmgr/TEST_MAPPING11
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java103
-rw-r--r--cmds/bootanimation/BootAnimation.cpp42
-rw-r--r--cmds/idmap2/Android.bp6
-rw-r--r--cmds/idmap2/idmap2/Create.cpp6
-rw-r--r--cmds/idmap2/idmap2/Dump.cpp2
-rw-r--r--cmds/idmap2/idmap2/Lookup.cpp39
-rw-r--r--cmds/idmap2/idmap2/Scan.cpp4
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.cpp4
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.h9
-rw-r--r--cmds/idmap2/include/idmap2/BinaryStreamVisitor.h11
-rw-r--r--cmds/idmap2/include/idmap2/Idmap.h19
-rw-r--r--cmds/idmap2/include/idmap2/PrettyPrintVisitor.h11
-rw-r--r--cmds/idmap2/include/idmap2/RawPrintVisitor.h11
-rw-r--r--cmds/idmap2/include/idmap2/ResourceMapping.h132
-rw-r--r--cmds/idmap2/include/idmap2/ResourceUtils.h19
-rw-r--r--cmds/idmap2/include/idmap2/Xml.h49
-rw-r--r--cmds/idmap2/include/idmap2/XmlParser.h147
-rw-r--r--cmds/idmap2/libidmap2/Idmap.cpp218
-rw-r--r--cmds/idmap2/libidmap2/ResourceMapping.cpp411
-rw-r--r--cmds/idmap2/libidmap2/ResourceUtils.cpp80
-rw-r--r--cmds/idmap2/libidmap2/Xml.cpp80
-rw-r--r--cmds/idmap2/libidmap2/XmlParser.cpp163
-rw-r--r--cmds/idmap2/libidmap2/ZipFile.cpp1
-rwxr-xr-xcmds/idmap2/static-checks.sh5
-rw-r--r--cmds/idmap2/tests/BinaryStreamVisitorTests.cpp5
-rw-r--r--cmds/idmap2/tests/IdmapTests.cpp13
-rw-r--r--cmds/idmap2/tests/PrettyPrintVisitorTests.cpp5
-rw-r--r--cmds/idmap2/tests/RawPrintVisitorTests.cpp7
-rw-r--r--cmds/idmap2/tests/ResourceMappingTests.cpp322
-rw-r--r--cmds/idmap2/tests/TestHelpers.h4
-rw-r--r--cmds/idmap2/tests/XmlParserTests.cpp174
-rw-r--r--cmds/idmap2/tests/XmlTests.cpp68
-rw-r--r--cmds/idmap2/tests/data/overlay/AndroidManifest.xml5
-rwxr-xr-xcmds/idmap2/tests/data/overlay/build2
-rw-r--r--cmds/idmap2/tests/data/overlay/overlay-no-name-static.apkbin1643 -> 3477 bytes
-rw-r--r--cmds/idmap2/tests/data/overlay/overlay-no-name.apkbin1599 -> 3389 bytes
-rw-r--r--cmds/idmap2/tests/data/overlay/overlay-static-1.apkbin1643 -> 3469 bytes
-rw-r--r--cmds/idmap2/tests/data/overlay/overlay-static-2.apkbin1643 -> 3469 bytes
-rw-r--r--cmds/idmap2/tests/data/overlay/overlay.apkbin1595 -> 3489 bytes
-rw-r--r--cmds/idmap2/tests/data/overlay/res/xml/overlays.xml23
-rw-r--r--cmds/idmap2/tests/data/overlay/res/xml/overlays_different_package.xml20
-rw-r--r--cmds/idmap2/tests/data/overlay/res/xml/overlays_inline.xml20
-rw-r--r--cmds/idmap2/tests/data/overlay/res/xml/overlays_swap.xml21
-rw-r--r--cmds/idmap2/tests/data/target/res/xml/test.xml19
-rw-r--r--cmds/idmap2/tests/data/target/target-no-overlayable.apkbin2263 -> 2749 bytes
-rw-r--r--cmds/idmap2/tests/data/target/target.apkbin5017 -> 5017 bytes
-rwxr-xr-xcmds/idmap2/valgrind.sh59
-rw-r--r--cmds/locksettings/TEST_MAPPING15
-rw-r--r--cmds/statsd/Android.bp161
-rw-r--r--cmds/statsd/OWNERS1
-rw-r--r--cmds/statsd/src/FieldValue.cpp33
-rw-r--r--cmds/statsd/src/FieldValue.h1
-rw-r--r--cmds/statsd/src/HashableDimensionKey.cpp10
-rw-r--r--cmds/statsd/src/HashableDimensionKey.h9
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h13
-rw-r--r--cmds/statsd/src/StatsService.cpp15
-rw-r--r--cmds/statsd/src/StatsService.h4
-rw-r--r--cmds/statsd/src/atoms.proto489
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.cpp29
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.h11
-rw-r--r--cmds/statsd/src/condition/ConditionTracker.h17
-rw-r--r--cmds/statsd/src/condition/ConditionWizard.cpp20
-rw-r--r--cmds/statsd/src/condition/ConditionWizard.h10
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp77
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.h11
-rw-r--r--cmds/statsd/src/condition/StateConditionTracker.cpp (renamed from cmds/statsd/src/condition/StateTracker.cpp)51
-rw-r--r--cmds/statsd/src/condition/StateConditionTracker.h (renamed from cmds/statsd/src/condition/StateTracker.h)30
-rw-r--r--cmds/statsd/src/external/GpuStatsPuller.cpp13
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp25
-rw-r--r--cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp99
-rw-r--r--cmds/statsd/src/external/SurfaceflingerStatsPuller.h48
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp7
-rw-r--r--cmds/statsd/src/logd/LogEvent.h3
-rw-r--r--cmds/statsd/src/matchers/matcher_util.cpp7
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp28
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.h7
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp255
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h7
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp10
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.h6
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp34
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.h11
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp63
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h235
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h11
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp44
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h11
-rw-r--r--cmds/statsd/src/metrics/duration_helper/DurationTracker.h6
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp22
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h2
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp30
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h2
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp231
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.h7
-rw-r--r--cmds/statsd/src/state/StateListener.h52
-rw-r--r--cmds/statsd/src/state/StateManager.cpp92
-rw-r--r--cmds/statsd/src/state/StateManager.h77
-rw-r--r--cmds/statsd/src/state/StateTracker.cpp159
-rw-r--r--cmds/statsd/src/state/StateTracker.h95
-rw-r--r--cmds/statsd/src/stats_log.proto33
-rw-r--r--cmds/statsd/src/stats_log_util.cpp2
-rw-r--r--cmds/statsd/src/statsd_config.proto41
-rw-r--r--cmds/statsd/tests/LogEntryMatcher_test.cpp41
-rw-r--r--cmds/statsd/tests/LogEvent_test.cpp4
-rw-r--r--cmds/statsd/tests/StatsLogProcessor_test.cpp312
-rw-r--r--cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp55
-rw-r--r--cmds/statsd/tests/condition/StateConditionTracker_test.cpp (renamed from cmds/statsd/tests/condition/StateTracker_test.cpp)6
-rw-r--r--cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp5
-rw-r--r--cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp961
-rw-r--r--cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp816
-rw-r--r--cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp814
-rw-r--r--cmds/statsd/tests/external/GpuStatsPuller_test.cpp5
-rw-r--r--cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp95
-rw-r--r--cmds/statsd/tests/metrics/CountMetricProducer_test.cpp24
-rw-r--r--cmds/statsd/tests/metrics/EventMetricProducer_test.cpp4
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp27
-rw-r--r--cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp26
-rw-r--r--cmds/statsd/tests/metrics/OringDurationTracker_test.cpp45
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp21
-rw-r--r--cmds/statsd/tests/metrics/metrics_test_helper.h8
-rw-r--r--cmds/statsd/tests/state/StateTracker_test.cpp356
-rw-r--r--cmds/statsd/tools/dogfood/Android.bp37
-rw-r--r--cmds/statsd/tools/dogfood/AndroidManifest.xml43
-rw-r--r--cmds/statsd/tools/dogfood/res/drawable-hdpi/ic_launcher.pngbin7783 -> 0 bytes
-rw-r--r--cmds/statsd/tools/dogfood/res/drawable-mdpi/ic_launcher.pngbin3760 -> 0 bytes
-rw-r--r--cmds/statsd/tools/dogfood/res/drawable-xhdpi/ic_launcher.pngbin12356 -> 0 bytes
-rw-r--r--cmds/statsd/tools/dogfood/res/drawable-xxhdpi/ic_launcher.pngbin24780 -> 0 bytes
-rw-r--r--cmds/statsd/tools/dogfood/res/layout/activity_main.xml162
-rw-r--r--cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config109
-rw-r--r--cmds/statsd/tools/dogfood/res/values/strings.xml57
-rw-r--r--cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java158
-rw-r--r--cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java361
-rw-r--r--cmds/statsd/tools/loadtest/Android.bp37
-rw-r--r--cmds/statsd/tools/loadtest/AndroidManifest.xml44
-rw-r--r--cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.pngbin7783 -> 0 bytes
-rw-r--r--cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.pngbin3760 -> 0 bytes
-rw-r--r--cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.pngbin12356 -> 0 bytes
-rw-r--r--cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.pngbin24780 -> 0 bytes
-rw-r--r--cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml208
-rw-r--r--cmds/statsd/tools/loadtest/res/layout/spinner_item.xml10
-rwxr-xr-xcmds/statsd/tools/loadtest/res/raw/loadtest_configbin2087 -> 0 bytes
-rw-r--r--cmds/statsd/tools/loadtest/res/values/integers.xml24
-rw-r--r--cmds/statsd/tools/loadtest/res/values/strings.xml36
-rwxr-xr-xcmds/statsd/tools/loadtest/run_loadtest.sh99
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java56
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java113
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java314
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java169
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java756
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java69
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java53
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java70
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java116
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java174
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java27
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java165
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java62
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java93
159 files changed, 4255 insertions, 8124 deletions
diff --git a/cmds/bmgr/TEST_MAPPING b/cmds/bmgr/TEST_MAPPING
new file mode 100644
index 000000000000..7c0e79e7692d
--- /dev/null
+++ b/cmds/bmgr/TEST_MAPPING
@@ -0,0 +1,11 @@
+{
+ "presubmit": [
+ ],
+ "postsubmit": [
+ ],
+ "imports": [
+ {
+ "path": "frameworks/base/services/backup"
+ }
+ ]
+}
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 680ccfc57ddf..ed717c491467 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -64,6 +64,10 @@ public class Bmgr {
private static final String BMGR_NOT_RUNNING_ERR =
"Error: Could not access the Backup Manager. Is the system running?";
+ private static final String BMGR_NOT_ACTIVATED_FOR_USER =
+ "Error: Backup Manager is not activated for user ";
+ private static final String BMGR_ERR_NO_RESTORESESSION_FOR_USER =
+ "Error: Could not get restore session for user ";
private static final String TRANSPORT_NOT_RUNNING_ERR =
"Error: Could not access the backup transport. Is the system running?";
private static final String PM_NOT_RUNNING_ERR =
@@ -121,6 +125,11 @@ public class Bmgr {
return;
}
+ if ("autorestore".equals(op)) {
+ doAutoRestore(userId);
+ return;
+ }
+
if ("enabled".equals(op)) {
doEnabled(userId);
return;
@@ -190,21 +199,45 @@ public class Bmgr {
showUsage();
}
- boolean isBackupActive(@UserIdInt int userId) {
+ private void handleRemoteException(RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+
+ private boolean isBackupActive(@UserIdInt int userId) {
try {
if (!mBmgr.isBackupServiceActive(userId)) {
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ System.err.println(BMGR_NOT_ACTIVATED_FOR_USER + userId);
return false;
}
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
return false;
}
return true;
}
+ private void doAutoRestore(int userId) {
+ String arg = nextArg();
+ if (arg == null) {
+ showUsage();
+ return;
+ }
+
+ try {
+ boolean enable = Boolean.parseBoolean(arg);
+ mBmgr.setAutoRestore(enable);
+ System.out.println(
+ "Auto restore is now "
+ + (enable ? "enabled" : "disabled")
+ + " for user "
+ + userId);
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ }
+ }
+
private String activatedToString(boolean activated) {
return activated ? "activated" : "deactivated";
}
@@ -214,8 +247,7 @@ public class Bmgr {
System.out.println("Backup Manager currently "
+ activatedToString(mBmgr.isBackupServiceActive(userId)));
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -230,8 +262,7 @@ public class Bmgr {
System.out.println("Backup Manager currently "
+ enableToString(isEnabled));
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -250,8 +281,7 @@ public class Bmgr {
showUsage();
return;
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -259,8 +289,7 @@ public class Bmgr {
try {
mBmgr.backupNowForUser(userId);
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -274,8 +303,7 @@ public class Bmgr {
try {
mBmgr.dataChangedForUser(userId, pkg);
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -292,8 +320,7 @@ public class Bmgr {
mBmgr.fullTransportBackupForUser(
userId, allPkgs.toArray(new String[allPkgs.size()]));
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
}
@@ -421,8 +448,7 @@ public class Bmgr {
try {
filteredPackages = mBmgr.filterAppsEligibleForBackupForUser(userId, packages);
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
backupNowPackages(userId, Arrays.asList(filteredPackages), nonIncrementalBackup,
monitorState);
@@ -455,8 +481,7 @@ public class Bmgr {
System.err.println("Unable to run backup");
}
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -506,8 +531,7 @@ public class Bmgr {
try {
mBmgr.cancelBackupsForUser(userId);
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
return;
}
@@ -537,8 +561,7 @@ public class Bmgr {
}
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -569,8 +592,7 @@ public class Bmgr {
}
});
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
return;
}
@@ -598,8 +620,7 @@ public class Bmgr {
mBmgr.clearBackupDataForUser(userId, transport, pkg);
System.out.println("Wiped backup data for " + pkg + " on " + transport);
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -632,8 +653,7 @@ public class Bmgr {
observer.waitForCompletion(30*1000L);
System.out.println("Initialization result: " + observer.result);
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -648,7 +668,7 @@ public class Bmgr {
try {
mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
if (mRestore == null) {
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
return;
}
@@ -658,8 +678,7 @@ public class Bmgr {
mRestore.endRestoreSession();
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -686,8 +705,7 @@ public class Bmgr {
System.out.println(pad + t);
}
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -805,7 +823,7 @@ public class Bmgr {
boolean didRestore = false;
mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
if (mRestore == null) {
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
return;
}
RestoreSet[] sets = null;
@@ -851,8 +869,7 @@ public class Bmgr {
System.out.println("done");
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -865,8 +882,7 @@ public class Bmgr {
}
}
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -886,8 +902,7 @@ public class Bmgr {
+ " for user "
+ userId);
} catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ handleRemoteException(e);
}
}
@@ -928,6 +943,7 @@ public class Bmgr {
System.err.println(" bmgr init TRANSPORT...");
System.err.println(" bmgr activate BOOL");
System.err.println(" bmgr activated");
+ System.err.println(" bmgr autorestore BOOL");
System.err.println("");
System.err.println("The '--user' option specifies the user on which the operation is run.");
System.err.println("It must be the first argument before the operation.");
@@ -1002,6 +1018,9 @@ public class Bmgr {
System.err.println("");
System.err.println("The 'activated' command reports the current activated/deactivated");
System.err.println("state of the backup mechanism.");
+ System.err.println("");
+ System.err.println("The 'autorestore' command enables or disables automatic restore when");
+ System.err.println("a new package is installed.");
}
private static class BackupMonitor extends IBackupManagerMonitor.Stub {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index db384baff4d7..e1cb7ca6a697 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -288,6 +288,48 @@ status_t BootAnimation::readyToRun() {
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::Transaction t;
+
+ // this guest property specifies multi-display IDs to show the boot animation
+ // multiple ids can be set with comma (,) as separator, for example:
+ // setprop boot.animation.displays 19260422155234049,19261083906282754
+ Vector<uint64_t> physicalDisplayIds;
+ char displayValue[PROPERTY_VALUE_MAX] = "";
+ property_get("boot.animation.displays", displayValue, "");
+ bool isValid = displayValue[0] != '\0';
+ if (isValid) {
+ char *p = displayValue;
+ while (*p) {
+ if (!isdigit(*p) && *p != ',') {
+ isValid = false;
+ break;
+ }
+ p ++;
+ }
+ if (!isValid)
+ SLOGE("Invalid syntax for the value of system prop: boot.animation.displays");
+ }
+ if (isValid) {
+ std::istringstream stream(displayValue);
+ for (PhysicalDisplayId id; stream >> id; ) {
+ physicalDisplayIds.add(id);
+ if (stream.peek() == ',')
+ stream.ignore();
+ }
+
+ // In the case of multi-display, boot animation shows on the specified displays
+ // in addition to the primary display
+ auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ constexpr uint32_t LAYER_STACK = 0;
+ for (auto id : physicalDisplayIds) {
+ if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
+ sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(id);
+ if (token != nullptr)
+ t.setDisplayLayerStack(token, LAYER_STACK);
+ }
+ }
+ t.setLayerStack(control, LAYER_STACK);
+ }
+
t.setLayer(control, 0x40000000)
.apply();
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 4c77ba402595..41a17064c3ba 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -43,9 +43,10 @@ cc_library {
"libidmap2/Policies.cpp",
"libidmap2/PrettyPrintVisitor.cpp",
"libidmap2/RawPrintVisitor.cpp",
+ "libidmap2/ResourceMapping.cpp",
"libidmap2/ResourceUtils.cpp",
"libidmap2/Result.cpp",
- "libidmap2/Xml.cpp",
+ "libidmap2/XmlParser.cpp",
"libidmap2/ZipFile.cpp",
],
export_include_dirs: ["include"],
@@ -97,9 +98,10 @@ cc_test {
"tests/PoliciesTests.cpp",
"tests/PrettyPrintVisitorTests.cpp",
"tests/RawPrintVisitorTests.cpp",
+ "tests/ResourceMappingTests.cpp",
"tests/ResourceUtilsTests.cpp",
"tests/ResultTests.cpp",
- "tests/XmlTests.cpp",
+ "tests/XmlParserTests.cpp",
"tests/ZipFileTests.cpp",
],
required: [
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index bb8d92737563..3ff6d3514331 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -50,7 +50,7 @@ Result<Unit> Create(const std::vector<std::string>& args) {
std::string overlay_apk_path;
std::string idmap_path;
std::vector<std::string> policies;
- bool ignore_overlayable;
+ bool ignore_overlayable = false;
const CommandLineOptions opts =
CommandLineOptions("idmap2 create")
@@ -99,8 +99,8 @@ Result<Unit> Create(const std::vector<std::string>& args) {
return Error("failed to load apk %s", overlay_apk_path.c_str());
}
- const auto idmap = Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path,
- *overlay_apk, fulfilled_policies, !ignore_overlayable);
+ const auto idmap =
+ Idmap::FromApkAssets(*target_apk, *overlay_apk, fulfilled_policies, !ignore_overlayable);
if (!idmap) {
return Error(idmap.GetError(), "failed to create idmap");
}
diff --git a/cmds/idmap2/idmap2/Dump.cpp b/cmds/idmap2/idmap2/Dump.cpp
index 8716bf313ed0..47f442aab235 100644
--- a/cmds/idmap2/idmap2/Dump.cpp
+++ b/cmds/idmap2/idmap2/Dump.cpp
@@ -39,7 +39,7 @@ using android::idmap2::Unit;
Result<Unit> Dump(const std::vector<std::string>& args) {
SYSTRACE << "Dump " << args;
std::string idmap_path;
- bool verbose;
+ bool verbose = false;
const CommandLineOptions opts =
CommandLineOptions("idmap2 dump")
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index b7ae9d090cee..c5cf9807b689 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -33,9 +33,10 @@
#include "androidfw/Util.h"
#include "idmap2/CommandLineOptions.h"
#include "idmap2/Idmap.h"
+#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
-#include "idmap2/Xml.h"
+#include "idmap2/XmlParser.h"
#include "idmap2/ZipFile.h"
#include "utils/String16.h"
#include "utils/String8.h"
@@ -57,8 +58,7 @@ using android::idmap2::IdmapHeader;
using android::idmap2::ResourceId;
using android::idmap2::Result;
using android::idmap2::Unit;
-using android::idmap2::Xml;
-using android::idmap2::ZipFile;
+using android::idmap2::utils::ExtractOverlayManifestInfo;
using android::util::Utf16ToUtf8;
namespace {
@@ -132,29 +132,6 @@ Result<std::string> WARN_UNUSED GetValue(const AssetManager2& am, ResourceId res
return out;
}
-Result<std::string> GetTargetPackageNameFromManifest(const std::string& apk_path) {
- const auto zip = ZipFile::Open(apk_path);
- if (!zip) {
- return Error("failed to open %s as zip", apk_path.c_str());
- }
- const auto entry = zip->Uncompress("AndroidManifest.xml");
- if (!entry) {
- return Error("failed to uncompress AndroidManifest.xml in %s", apk_path.c_str());
- }
- const auto xml = Xml::Create(entry->buf, entry->size);
- if (!xml) {
- return Error("failed to create XML buffer");
- }
- const auto tag = xml->FindTag("overlay");
- if (!tag) {
- return Error("failed to find <overlay> tag");
- }
- const auto iter = tag->find("targetPackage");
- if (iter == tag->end()) {
- return Error("failed to find targetPackage attribute");
- }
- return iter->second;
-}
} // namespace
Result<Unit> Lookup(const std::vector<std::string>& args) {
@@ -202,12 +179,12 @@ Result<Unit> Lookup(const std::vector<std::string>& args) {
}
apk_assets.push_back(std::move(target_apk));
- const Result<std::string> package_name =
- GetTargetPackageNameFromManifest(idmap_header->GetOverlayPath().to_string());
- if (!package_name) {
- return Error("failed to parse android:targetPackage from overlay manifest");
+ auto manifest_info = ExtractOverlayManifestInfo(idmap_header->GetOverlayPath().to_string(),
+ true /* assert_overlay */);
+ if (!manifest_info) {
+ return manifest_info.GetError();
}
- target_package_name = *package_name;
+ target_package_name = (*manifest_info).target_package;
} else if (target_path != idmap_header->GetTargetPath()) {
return Error("different target APKs (expected target APK %s but %s has target APK %s)",
target_path.c_str(), idmap_path.c_str(),
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index da8c06e5f74f..e643ab567644 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -33,7 +33,7 @@
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
-#include "idmap2/Xml.h"
+#include "idmap2/XmlParser.h"
#include "idmap2/ZipFile.h"
using android::idmap2::CommandLineOptions;
@@ -98,6 +98,7 @@ Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector
}
std::vector<std::string> PoliciesForPath(const std::string& apk_path) {
+ // clang-format off
static const std::vector<std::pair<std::string, std::string>> values = {
{"/odm/", kPolicyOdm},
{"/oem/", kPolicyOem},
@@ -106,6 +107,7 @@ std::vector<std::string> PoliciesForPath(const std::string& apk_path) {
{"/system_ext/", kPolicySystem},
{"/vendor/", kPolicyVendor},
};
+ // clang-format on
std::vector<std::string> fulfilled_policies = {kPolicyPublic};
for (auto const& pair : values) {
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index 8ee79f61520a..4aabf8399a25 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -137,8 +137,8 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path,
return error("failed to load apk " + overlay_apk_path);
}
- const auto idmap = Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path,
- *overlay_apk, policy_bitmask, enforce_overlayable);
+ const auto idmap =
+ Idmap::FromApkAssets(*target_apk, *overlay_apk, policy_bitmask, enforce_overlayable);
if (!idmap) {
return error(idmap.GetErrorMessage());
}
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index 1aab0598449b..94d2af49260c 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -34,18 +34,19 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
}
binder::Status getIdmapPath(const std::string& overlay_apk_path, int32_t user_id,
- std::string* _aidl_return);
+ std::string* _aidl_return) override;
binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id,
- bool* _aidl_return);
+ bool* _aidl_return) override;
binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t fulfilled_policies,
- bool enforce_overlayable, int32_t user_id, bool* _aidl_return);
+ bool enforce_overlayable, int32_t user_id,
+ bool* _aidl_return) override;
binder::Status createIdmap(const std::string& target_apk_path,
const std::string& overlay_apk_path, int32_t fulfilled_policies,
bool enforce_overlayable, int32_t user_id,
- std::unique_ptr<std::string>* _aidl_return);
+ std::unique_ptr<std::string>* _aidl_return) override;
};
} // namespace android::os
diff --git a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
index 2c3e9d321881..1a0d4438f1b3 100644
--- a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
+++ b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
@@ -29,11 +29,12 @@ class BinaryStreamVisitor : public Visitor {
public:
explicit BinaryStreamVisitor(std::ostream& stream) : stream_(stream) {
}
- virtual void visit(const Idmap& idmap);
- virtual void visit(const IdmapHeader& header);
- virtual void visit(const IdmapData& data);
- virtual void visit(const IdmapData::Header& header);
- virtual void visit(const IdmapData::TypeEntry& type_entry);
+ ~BinaryStreamVisitor() override = default;
+ void visit(const Idmap& idmap) override;
+ void visit(const IdmapHeader& header) override;
+ void visit(const IdmapData& data) override;
+ void visit(const IdmapData::Header& header) override;
+ void visit(const IdmapData::TypeEntry& type_entry) override;
private:
void Write16(uint16_t value);
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index ebbb5ffc989d..f2cae58b910a 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -56,20 +56,14 @@
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
#include "idmap2/Policies.h"
+#include "idmap2/ResourceMapping.h"
namespace android::idmap2 {
class Idmap;
class Visitor;
-// use typedefs to let the compiler warn us about implicit casts
-typedef uint32_t ResourceId; // 0xpptteeee
-typedef uint8_t PackageId; // pp in 0xpptteeee
-typedef uint8_t TypeId; // tt in 0xpptteeee
-typedef uint16_t EntryId; // eeee in 0xpptteeee
-
static constexpr const ResourceId kPadding = 0xffffffffu;
-
static constexpr const EntryId kNoEntry = 0xffffu;
// magic number: all idmap files start with this
@@ -155,7 +149,7 @@ class IdmapData {
PackageId target_package_id_;
uint16_t type_count_;
- friend Idmap;
+ friend IdmapData;
DISALLOW_COPY_AND_ASSIGN(Header);
};
@@ -194,12 +188,15 @@ class IdmapData {
uint16_t entry_offset_;
std::vector<EntryId> entries_;
- friend Idmap;
+ friend IdmapData;
DISALLOW_COPY_AND_ASSIGN(TypeEntry);
};
static std::unique_ptr<const IdmapData> FromBinaryStream(std::istream& stream);
+ static Result<std::unique_ptr<const IdmapData>> FromResourceMapping(
+ const ResourceMapping& resource_mapping);
+
inline const std::unique_ptr<const Header>& GetHeader() const {
return header_;
}
@@ -232,9 +229,7 @@ class Idmap {
// file is used; change this in the next version of idmap to use a named
// package instead; also update FromApkAssets to take additional parameters:
// the target and overlay package names
- static Result<std::unique_ptr<const Idmap>> FromApkAssets(const std::string& target_apk_path,
- const ApkAssets& target_apk_assets,
- const std::string& overlay_apk_path,
+ static Result<std::unique_ptr<const Idmap>> FromApkAssets(const ApkAssets& target_apk_assets,
const ApkAssets& overlay_apk_assets,
const PolicyBitmask& fulfilled_policies,
bool enforce_overlayable);
diff --git a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
index 5111bb2eaab2..f0f141a3757c 100644
--- a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
+++ b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
@@ -33,11 +33,12 @@ class PrettyPrintVisitor : public Visitor {
public:
explicit PrettyPrintVisitor(std::ostream& stream) : stream_(stream) {
}
- virtual void visit(const Idmap& idmap);
- virtual void visit(const IdmapHeader& header);
- virtual void visit(const IdmapData& data);
- virtual void visit(const IdmapData::Header& header);
- virtual void visit(const IdmapData::TypeEntry& type_entry);
+ ~PrettyPrintVisitor() override = default;
+ void visit(const Idmap& idmap) override;
+ void visit(const IdmapHeader& header) override;
+ void visit(const IdmapData& data) override;
+ void visit(const IdmapData::Header& header) override;
+ void visit(const IdmapData::TypeEntry& type_entry) override;
private:
std::ostream& stream_;
diff --git a/cmds/idmap2/include/idmap2/RawPrintVisitor.h b/cmds/idmap2/include/idmap2/RawPrintVisitor.h
index 2e543d4fabdd..cd3897109a32 100644
--- a/cmds/idmap2/include/idmap2/RawPrintVisitor.h
+++ b/cmds/idmap2/include/idmap2/RawPrintVisitor.h
@@ -34,11 +34,12 @@ class RawPrintVisitor : public Visitor {
public:
explicit RawPrintVisitor(std::ostream& stream) : stream_(stream), offset_(0) {
}
- virtual void visit(const Idmap& idmap);
- virtual void visit(const IdmapHeader& header);
- virtual void visit(const IdmapData& data);
- virtual void visit(const IdmapData::Header& header);
- virtual void visit(const IdmapData::TypeEntry& type_entry);
+ ~RawPrintVisitor() override = default;
+ void visit(const Idmap& idmap) override;
+ void visit(const IdmapHeader& header) override;
+ void visit(const IdmapData& data) override;
+ void visit(const IdmapData::Header& header) override;
+ void visit(const IdmapData::TypeEntry& type_entry) override;
private:
void print(uint16_t value, const char* fmt, ...);
diff --git a/cmds/idmap2/include/idmap2/ResourceMapping.h b/cmds/idmap2/include/idmap2/ResourceMapping.h
new file mode 100644
index 000000000000..c3e1ef06c20f
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/ResourceMapping.h
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_RESOURCEMAPPING_H_
+#define IDMAP2_INCLUDE_IDMAP2_RESOURCEMAPPING_H_
+
+#include <map>
+#include <memory>
+#include <utility>
+
+#include "androidfw/ApkAssets.h"
+#include "idmap2/Policies.h"
+#include "idmap2/ResourceUtils.h"
+#include "idmap2/Result.h"
+#include "idmap2/XmlParser.h"
+
+using android::idmap2::utils::OverlayManifestInfo;
+
+namespace android::idmap2 {
+
+struct TargetValue {
+ typedef uint8_t DataType;
+ typedef uint32_t DataValue;
+ DataType data_type;
+ DataValue data_value;
+};
+
+using TargetResourceMap = std::map<ResourceId, TargetValue>;
+using OverlayResourceMap = std::map<ResourceId, ResourceId>;
+
+class ResourceMapping {
+ public:
+ // Creates a ResourceMapping using the target and overlay APKs. Setting enforce_overlayable to
+ // `false` disables all overlayable and policy enforcement: this is intended for backwards
+ // compatibility pre-Q and unit tests.
+ static Result<ResourceMapping> FromApkAssets(const ApkAssets& target_apk_assets,
+ const ApkAssets& overlay_apk_assets,
+ const OverlayManifestInfo& overlay_info,
+ const PolicyBitmask& fulfilled_policies,
+ bool enforce_overlayable);
+
+ // Retrieves the mapping of target resource id to overlay value.
+ inline TargetResourceMap GetTargetToOverlayMap() const {
+ return target_map_;
+ }
+
+ // Retrieves the mapping of overlay resource id to target resource id. This allows a reference to
+ // an overlay resource to appear as a reference to its corresponding target resource at runtime.
+ OverlayResourceMap GetOverlayToTargetMap() const;
+
+ // Retrieves the build-time package id of the target package.
+ inline uint32_t GetTargetPackageId() const {
+ return target_package_id_;
+ }
+
+ // Retrieves the build-time package id of the overlay package.
+ inline uint32_t GetOverlayPackageId() const {
+ return overlay_package_id_;
+ }
+
+ // Retrieves the offset that was added to the index of inline string overlay values so the indices
+ // do not collide with the indices of the overlay resource table string pool.
+ inline uint32_t GetStringPoolOffset() const {
+ return string_pool_offset_;
+ }
+
+ // Retrieves the raw string pool data from the xml referenced in android:resourcesMap.
+ inline const std::pair<const uint8_t*, uint32_t> GetStringPoolData() const {
+ return std::make_pair(string_pool_data_.get(), string_pool_data_length_);
+ }
+
+ private:
+ ResourceMapping() = default;
+
+ // Apps a mapping of target resource id to the type and value of the data that overlays the
+ // target resource. The data_type is the runtime format of the data value (see
+ // Res_value::dataType). If rewrite_overlay_reference is `true` then references to an overlay
+ // resource should appear as a reference to its corresponding target resource at runtime.
+ Result<Unit> AddMapping(ResourceId target_resource, TargetValue::DataType data_type,
+ TargetValue::DataValue data_value, bool rewrite_overlay_reference);
+
+ // Removes the overlay value mapping for the target resource.
+ void RemoveMapping(ResourceId target_resource);
+
+ // Parses the mapping of target resources to overlay resources to generate a ResourceMapping.
+ static Result<ResourceMapping> CreateResourceMapping(const AssetManager2* target_am,
+ const LoadedPackage* target_package,
+ const LoadedPackage* overlay_package,
+ size_t string_pool_offset,
+ const XmlParser& overlay_parser);
+
+ // Generates a ResourceMapping that maps target resources to overlay resources by name. To overlay
+ // a target resource, a resource must exist in the overlay with the same type and entry name as
+ // the target resource.
+ static Result<ResourceMapping> CreateResourceMappingLegacy(const AssetManager2* target_am,
+ const AssetManager2* overlay_am,
+ const LoadedPackage* target_package,
+ const LoadedPackage* overlay_package);
+
+ // Removes resources that do not pass policy or overlayable checks of the target package.
+ void FilterOverlayableResources(const AssetManager2* target_am,
+ const LoadedPackage* target_package,
+ const LoadedPackage* overlay_package,
+ const OverlayManifestInfo& overlay_info,
+ const PolicyBitmask& fulfilled_policies);
+
+ TargetResourceMap target_map_;
+ std::multimap<ResourceId, ResourceId> overlay_map_;
+
+ uint32_t target_package_id_ = 0;
+ uint32_t overlay_package_id_ = 0;
+ uint32_t string_pool_offset_ = 0;
+ uint32_t string_pool_data_length_ = 0;
+ std::unique_ptr<uint8_t[]> string_pool_data_ = nullptr;
+};
+
+} // namespace android::idmap2
+
+#endif // IDMAP2_INCLUDE_IDMAP2_RESOURCEMAPPING_H_
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index 9a0c2abced5a..abc2df1a147f 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -21,17 +21,28 @@
#include <string>
#include "androidfw/AssetManager2.h"
-#include "idmap2/Idmap.h"
#include "idmap2/Result.h"
#include "idmap2/ZipFile.h"
-namespace android::idmap2::utils {
+namespace android::idmap2 {
+
+// use typedefs to let the compiler warn us about implicit casts
+typedef uint32_t ResourceId; // 0xpptteeee
+typedef uint8_t PackageId; // pp in 0xpptteeee
+typedef uint8_t TypeId; // tt in 0xpptteeee
+typedef uint16_t EntryId; // eeee in 0xpptteeee
+
+#define EXTRACT_TYPE(resid) ((0x00ff0000 & (resid)) >> 16)
+#define EXTRACT_ENTRY(resid) (0x0000ffff & (resid))
+
+namespace utils {
struct OverlayManifestInfo {
std::string target_package; // NOLINT(misc-non-private-member-variables-in-classes)
std::string target_name; // NOLINT(misc-non-private-member-variables-in-classes)
std::string requiredSystemPropertyName; // NOLINT(misc-non-private-member-variables-in-classes)
std::string requiredSystemPropertyValue; // NOLINT(misc-non-private-member-variables-in-classes)
+ uint32_t resource_mapping; // NOLINT(misc-non-private-member-variables-in-classes)
bool is_static; // NOLINT(misc-non-private-member-variables-in-classes)
int priority = -1; // NOLINT(misc-non-private-member-variables-in-classes)
};
@@ -41,6 +52,8 @@ Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
Result<std::string> ResToTypeEntryName(const AssetManager2& am, ResourceId resid);
-} // namespace android::idmap2::utils
+} // namespace utils
+
+} // namespace android::idmap2
#endif // IDMAP2_INCLUDE_IDMAP2_RESOURCEUTILS_H_
diff --git a/cmds/idmap2/include/idmap2/Xml.h b/cmds/idmap2/include/idmap2/Xml.h
deleted file mode 100644
index dd89dee0f64f..000000000000
--- a/cmds/idmap2/include/idmap2/Xml.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef IDMAP2_INCLUDE_IDMAP2_XML_H_
-#define IDMAP2_INCLUDE_IDMAP2_XML_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "android-base/macros.h"
-#include "androidfw/ResourceTypes.h"
-#include "utils/String16.h"
-
-namespace android::idmap2 {
-
-class Xml {
- public:
- static std::unique_ptr<const Xml> Create(const uint8_t* data, size_t size, bool copyData = false);
-
- std::unique_ptr<std::map<std::string, std::string>> FindTag(const std::string& name) const;
-
- ~Xml();
-
- private:
- Xml() {
- }
-
- mutable ResXMLTree xml_;
-
- DISALLOW_COPY_AND_ASSIGN(Xml);
-};
-
-} // namespace android::idmap2
-
-#endif // IDMAP2_INCLUDE_IDMAP2_XML_H_
diff --git a/cmds/idmap2/include/idmap2/XmlParser.h b/cmds/idmap2/include/idmap2/XmlParser.h
new file mode 100644
index 000000000000..972a6d7e3427
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/XmlParser.h
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_XMLPARSER_H_
+#define IDMAP2_INCLUDE_IDMAP2_XMLPARSER_H_
+
+#include <iostream>
+#include <map>
+#include <memory>
+#include <string>
+
+#include "Result.h"
+#include "android-base/macros.h"
+#include "androidfw/ResourceTypes.h"
+#include "utils/String16.h"
+
+namespace android::idmap2 {
+
+class XmlParser {
+ public:
+ using Event = ResXMLParser::event_code_t;
+ class iterator;
+
+ class Node {
+ public:
+ Event event() const;
+ std::string name() const;
+
+ Result<std::string> GetAttributeStringValue(const std::string& name) const;
+ Result<Res_value> GetAttributeValue(const std::string& name) const;
+
+ bool operator==(const Node& rhs) const;
+ bool operator!=(const Node& rhs) const;
+
+ private:
+ explicit Node(const ResXMLTree& tree);
+ Node(const ResXMLTree& tree, const ResXMLParser::ResXMLPosition& pos);
+
+ // Retrieves/Sets the position of the position of the xml parser in the xml tree.
+ ResXMLParser::ResXMLPosition get_position() const;
+ void set_position(const ResXMLParser::ResXMLPosition& pos);
+
+ // If `inner_child` is true, seek advances the parser to the first inner child of the current
+ // node. Otherwise, seek advances the parser to the following node. Returns false if there is
+ // no node to seek to.
+ bool Seek(bool inner_child);
+
+ ResXMLParser parser_;
+ friend iterator;
+ };
+
+ class iterator {
+ public:
+ iterator(const iterator& other) : iterator(other.tree_, other.iter_) {
+ }
+
+ inline iterator& operator=(const iterator& rhs) {
+ iter_.set_position(rhs.iter_.get_position());
+ return *this;
+ }
+
+ inline bool operator==(const iterator& rhs) const {
+ return iter_ == rhs.iter_;
+ }
+
+ inline bool operator!=(const iterator& rhs) const {
+ return !(*this == rhs);
+ }
+
+ inline iterator operator++() {
+ // Seek to the following xml node.
+ iter_.Seek(false /* inner_child */);
+ return *this;
+ }
+
+ iterator begin() const {
+ iterator child_it(*this);
+ // Seek to the first inner child of the current node.
+ child_it.iter_.Seek(true /* inner_child */);
+ return child_it;
+ }
+
+ iterator end() const {
+ iterator child_it = begin();
+ while (child_it.iter_.Seek(false /* inner_child */)) {
+ // Continue iterating until the end tag is found.
+ }
+
+ return child_it;
+ }
+
+ inline const Node operator*() {
+ return Node(tree_, iter_.get_position());
+ }
+
+ inline const Node* operator->() {
+ return &iter_;
+ }
+
+ private:
+ explicit iterator(const ResXMLTree& tree) : tree_(tree), iter_(Node(tree)) {
+ }
+ iterator(const ResXMLTree& tree, const Node& node)
+ : tree_(tree), iter_(Node(tree, node.get_position())) {
+ }
+
+ const ResXMLTree& tree_;
+ Node iter_;
+ friend XmlParser;
+ };
+
+ // Creates a new xml parser beginning at the first tag.
+ static Result<std::unique_ptr<const XmlParser>> Create(const void* data, size_t size,
+ bool copy_data = false);
+ ~XmlParser();
+
+ inline iterator tree_iterator() const {
+ return iterator(tree_);
+ }
+
+ inline const ResStringPool& get_strings() const {
+ return tree_.getStrings();
+ }
+
+ private:
+ XmlParser() = default;
+ mutable ResXMLTree tree_;
+
+ DISALLOW_COPY_AND_ASSIGN(XmlParser);
+};
+
+} // namespace android::idmap2
+
+#endif // IDMAP2_INCLUDE_IDMAP2_XMLPARSER_H_
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 4649675965db..389ade59200c 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -30,6 +30,7 @@
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
#include "androidfw/AssetManager2.h"
+#include "idmap2/ResourceMapping.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
@@ -41,10 +42,6 @@ namespace android::idmap2 {
namespace {
-#define EXTRACT_TYPE(resid) ((0x00ff0000 & (resid)) >> 16)
-
-#define EXTRACT_ENTRY(resid) (0x0000ffff & (resid))
-
class MatchingResources {
public:
void Add(ResourceId target_resid, ResourceId overlay_resid) {
@@ -97,28 +94,6 @@ bool WARN_UNUSED ReadString(std::istream& stream, char out[kIdmapStringLength])
return true;
}
-ResourceId NameToResid(const AssetManager2& am, const std::string& name) {
- return am.GetResourceId(name);
-}
-
-// TODO(martenkongstad): scan for package name instead of assuming package at index 0
-//
-// idmap version 0x01 naively assumes that the package to use is always the first ResTable_package
-// in the resources.arsc blob. In most cases, there is only a single ResTable_package anyway, so
-// this assumption tends to work out. That said, the correct thing to do is to scan
-// resources.arsc for a package with a given name as read from the package manifest instead of
-// relying on a hard-coded index. This however requires storing the package name in the idmap
-// header, which in turn requires incrementing the idmap version. Because the initial version of
-// idmap2 is compatible with idmap, this will have to wait for now.
-const LoadedPackage* GetPackageAtIndex0(const LoadedArsc& loaded_arsc) {
- const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc.GetPackages();
- if (packages.empty()) {
- return nullptr;
- }
- int id = packages[0]->GetPackageId();
- return loaded_arsc.GetPackageById(id);
-}
-
Result<uint32_t> GetCrc(const ZipFile& zip) {
const Result<uint32_t> a = zip.Crc("resources.arsc");
const Result<uint32_t> b = zip.Crc("AndroidManifest.xml");
@@ -266,95 +241,57 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromBinaryStream(std::istream& strea
return {std::move(idmap)};
}
-std::string ConcatPolicies(const std::vector<std::string>& policies) {
- std::string message;
- for (const std::string& policy : policies) {
- if (!message.empty()) {
- message.append("|");
- }
- message.append(policy);
+Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping(
+ const ResourceMapping& resource_mapping) {
+ if (resource_mapping.GetTargetToOverlayMap().empty()) {
+ return Error("no resources were overlaid");
}
- return message;
-}
-
-Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
- const utils::OverlayManifestInfo& overlay_info,
- const PolicyBitmask& fulfilled_policies, const ResourceId& resid) {
- static constexpr const PolicyBitmask sDefaultPolicies =
- PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION |
- PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION |
- PolicyFlags::POLICY_PRODUCT_PARTITION | PolicyFlags::POLICY_SIGNATURE;
-
- // If the resource does not have an overlayable definition, allow the resource to be overlaid if
- // the overlay is preinstalled or signed with the same signature as the target.
- if (!target_package.DefinesOverlayable()) {
- return (sDefaultPolicies & fulfilled_policies) != 0
- ? Result<Unit>({})
- : Error(
- "overlay must be preinstalled or signed with the same signature as the "
- "target");
- }
-
- const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(resid);
- if (overlayable_info == nullptr) {
- // Do not allow non-overlayable resources to be overlaid.
- return Error("resource has no overlayable declaration");
- }
+ MatchingResources matching_resources;
+ for (const auto mapping : resource_mapping.GetTargetToOverlayMap()) {
+ if (mapping.second.data_type != Res_value::TYPE_REFERENCE) {
+ // The idmap format must change to support non-references.
+ continue;
+ }
- if (overlay_info.target_name != overlayable_info->name) {
- // If the overlay supplies a target overlayable name, the resource must belong to the
- // overlayable defined with the specified name to be overlaid.
- return Error("<overlay> android:targetName '%s' does not match overlayable name '%s'",
- overlay_info.target_name.c_str(), overlayable_info->name.c_str());
+ matching_resources.Add(mapping.first, mapping.second.data_value);
}
- // Enforce policy restrictions if the resource is declared as overlayable.
- if ((overlayable_info->policy_flags & fulfilled_policies) == 0) {
- return Error("overlay with policies '%s' does not fulfill any overlayable policies '%s'",
- ConcatPolicies(BitmaskToPolicies(fulfilled_policies)).c_str(),
- ConcatPolicies(BitmaskToPolicies(overlayable_info->policy_flags)).c_str());
+ // encode idmap data
+ std::unique_ptr<IdmapData> data(new IdmapData());
+ const auto types_end = matching_resources.Map().cend();
+ for (auto ti = matching_resources.Map().cbegin(); ti != types_end; ++ti) {
+ auto ei = ti->second.cbegin();
+ std::unique_ptr<IdmapData::TypeEntry> type(new IdmapData::TypeEntry());
+ type->target_type_id_ = EXTRACT_TYPE(ei->first);
+ type->overlay_type_id_ = EXTRACT_TYPE(ei->second);
+ type->entry_offset_ = EXTRACT_ENTRY(ei->first);
+ EntryId last_target_entry = kNoEntry;
+ for (; ei != ti->second.cend(); ++ei) {
+ if (last_target_entry != kNoEntry) {
+ int count = EXTRACT_ENTRY(ei->first) - last_target_entry - 1;
+ type->entries_.insert(type->entries_.end(), count, kNoEntry);
+ }
+ type->entries_.push_back(EXTRACT_ENTRY(ei->second));
+ last_target_entry = EXTRACT_ENTRY(ei->first);
+ }
+ data->type_entries_.push_back(std::move(type));
}
- return Result<Unit>({});
+ std::unique_ptr<IdmapData::Header> data_header(new IdmapData::Header());
+ data_header->target_package_id_ = resource_mapping.GetTargetPackageId();
+ data_header->type_count_ = data->type_entries_.size();
+ data->header_ = std::move(data_header);
+ return {std::move(data)};
}
-Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const std::string& target_apk_path,
- const ApkAssets& target_apk_assets,
- const std::string& overlay_apk_path,
+Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const ApkAssets& target_apk_assets,
const ApkAssets& overlay_apk_assets,
const PolicyBitmask& fulfilled_policies,
bool enforce_overlayable) {
SYSTRACE << "Idmap::FromApkAssets";
- AssetManager2 target_asset_manager;
- if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) {
- return Error("failed to create target asset manager");
- }
-
- AssetManager2 overlay_asset_manager;
- if (!overlay_asset_manager.SetApkAssets({&overlay_apk_assets}, true, false)) {
- return Error("failed to create overlay asset manager");
- }
-
- const LoadedArsc* target_arsc = target_apk_assets.GetLoadedArsc();
- if (target_arsc == nullptr) {
- return Error("failed to load target resources.arsc");
- }
-
- const LoadedArsc* overlay_arsc = overlay_apk_assets.GetLoadedArsc();
- if (overlay_arsc == nullptr) {
- return Error("failed to load overlay resources.arsc");
- }
-
- const LoadedPackage* target_pkg = GetPackageAtIndex0(*target_arsc);
- if (target_pkg == nullptr) {
- return Error("failed to load target package from resources.arsc");
- }
-
- const LoadedPackage* overlay_pkg = GetPackageAtIndex0(*overlay_arsc);
- if (overlay_pkg == nullptr) {
- return Error("failed to load overlay package from resources.arsc");
- }
+ const std::string& target_apk_path = target_apk_assets.GetPath();
+ const std::string& overlay_apk_path = overlay_apk_assets.GetPath();
const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_apk_path);
if (!target_zip) {
@@ -366,11 +303,6 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const std::string& tar
return Error("failed to open overlay as zip");
}
- auto overlay_info = utils::ExtractOverlayManifestInfo(overlay_apk_path);
- if (!overlay_info) {
- return overlay_info.GetError();
- }
-
std::unique_ptr<IdmapHeader> header(new IdmapHeader());
header->magic_ = kIdmapMagic;
header->version_ = kIdmapCurrentVersion;
@@ -395,7 +327,7 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const std::string& tar
memcpy(header->target_path_, target_apk_path.data(), target_apk_path.size());
if (overlay_apk_path.size() > sizeof(header->overlay_path_)) {
- return Error("overlay apk path \"%s\" longer than maximum size %zu", target_apk_path.c_str(),
+ return Error("overlay apk path \"%s\" longer than maximum size %zu", overlay_apk_path.c_str(),
sizeof(header->target_path_));
}
memset(header->overlay_path_, 0, sizeof(header->overlay_path_));
@@ -404,70 +336,24 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const std::string& tar
std::unique_ptr<Idmap> idmap(new Idmap());
idmap->header_ = std::move(header);
- // find the resources that exist in both packages
- MatchingResources matching_resources;
- const auto end = overlay_pkg->end();
- for (auto iter = overlay_pkg->begin(); iter != end; ++iter) {
- const ResourceId overlay_resid = *iter;
- Result<std::string> name = utils::ResToTypeEntryName(overlay_asset_manager, overlay_resid);
- if (!name) {
- continue;
- }
- // prepend "<package>:" to turn name into "<package>:<type>/<name>"
- const std::string full_name =
- base::StringPrintf("%s:%s", target_pkg->GetPackageName().c_str(), name->c_str());
- const ResourceId target_resid = NameToResid(target_asset_manager, full_name);
- if (target_resid == 0) {
- continue;
- }
-
- if (enforce_overlayable) {
- Result<Unit> success =
- CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid);
- if (!success) {
- LOG(WARNING) << "overlay \"" << overlay_apk_path
- << "\" is not allowed to overlay resource \"" << full_name
- << "\": " << success.GetErrorMessage();
- continue;
- }
- }
-
- matching_resources.Add(target_resid, overlay_resid);
+ auto overlay_info = utils::ExtractOverlayManifestInfo(overlay_apk_path);
+ if (!overlay_info) {
+ return overlay_info.GetError();
}
- if (matching_resources.Map().empty()) {
- return Error("overlay \"%s\" does not successfully overlay any resource",
- overlay_apk_path.c_str());
+ auto resource_mapping =
+ ResourceMapping::FromApkAssets(target_apk_assets, overlay_apk_assets, *overlay_info,
+ fulfilled_policies, enforce_overlayable);
+ if (!resource_mapping) {
+ return resource_mapping.GetError();
}
- // encode idmap data
- std::unique_ptr<IdmapData> data(new IdmapData());
- const auto types_end = matching_resources.Map().cend();
- for (auto ti = matching_resources.Map().cbegin(); ti != types_end; ++ti) {
- auto ei = ti->second.cbegin();
- std::unique_ptr<IdmapData::TypeEntry> type(new IdmapData::TypeEntry());
- type->target_type_id_ = EXTRACT_TYPE(ei->first);
- type->overlay_type_id_ = EXTRACT_TYPE(ei->second);
- type->entry_offset_ = EXTRACT_ENTRY(ei->first);
- EntryId last_target_entry = kNoEntry;
- for (; ei != ti->second.cend(); ++ei) {
- if (last_target_entry != kNoEntry) {
- int count = EXTRACT_ENTRY(ei->first) - last_target_entry - 1;
- type->entries_.insert(type->entries_.end(), count, kNoEntry);
- }
- type->entries_.push_back(EXTRACT_ENTRY(ei->second));
- last_target_entry = EXTRACT_ENTRY(ei->first);
- }
- data->type_entries_.push_back(std::move(type));
+ auto idmap_data = IdmapData::FromResourceMapping(*resource_mapping);
+ if (!idmap_data) {
+ return idmap_data.GetError();
}
- std::unique_ptr<IdmapData::Header> data_header(new IdmapData::Header());
- data_header->target_package_id_ = target_pkg->GetPackageId();
- data_header->type_count_ = data->type_entries_.size();
- data->header_ = std::move(data_header);
-
- idmap->data_.push_back(std::move(data));
-
+ idmap->data_.push_back(std::move(*idmap_data));
return {std::move(idmap)};
}
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
new file mode 100644
index 000000000000..95ae626664dd
--- /dev/null
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -0,0 +1,411 @@
+/*
+ * 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 "idmap2/ResourceMapping.h"
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android-base/stringprintf.h"
+#include "idmap2/ResourceUtils.h"
+
+using android::base::StringPrintf;
+using android::idmap2::utils::ResToTypeEntryName;
+
+namespace android::idmap2 {
+
+namespace {
+
+#define EXTRACT_PACKAGE(resid) ((0xff000000 & (resid)) >> 24)
+
+std::string ConcatPolicies(const std::vector<std::string>& policies) {
+ std::string message;
+ for (const std::string& policy : policies) {
+ if (!message.empty()) {
+ message.append("|");
+ }
+ message.append(policy);
+ }
+
+ return message;
+}
+
+Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
+ const OverlayManifestInfo& overlay_info,
+ const PolicyBitmask& fulfilled_policies,
+ const ResourceId& target_resource) {
+ static constexpr const PolicyBitmask sDefaultPolicies =
+ PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION |
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION |
+ PolicyFlags::POLICY_PRODUCT_PARTITION | PolicyFlags::POLICY_SIGNATURE;
+
+ // If the resource does not have an overlayable definition, allow the resource to be overlaid if
+ // the overlay is preinstalled or signed with the same signature as the target.
+ if (!target_package.DefinesOverlayable()) {
+ return (sDefaultPolicies & fulfilled_policies) != 0
+ ? Result<Unit>({})
+ : Error(
+ "overlay must be preinstalled or signed with the same signature as the "
+ "target");
+ }
+
+ const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(target_resource);
+ if (overlayable_info == nullptr) {
+ // Do not allow non-overlayable resources to be overlaid.
+ return Error("target resource has no overlayable declaration");
+ }
+
+ if (overlay_info.target_name != overlayable_info->name) {
+ // If the overlay supplies a target overlayable name, the resource must belong to the
+ // overlayable defined with the specified name to be overlaid.
+ return Error(R"(<overlay> android:targetName "%s" does not match overlayable name "%s")",
+ overlay_info.target_name.c_str(), overlayable_info->name.c_str());
+ }
+
+ // Enforce policy restrictions if the resource is declared as overlayable.
+ if ((overlayable_info->policy_flags & fulfilled_policies) == 0) {
+ return Error(R"(overlay with policies "%s" does not fulfill any overlayable policies "%s")",
+ ConcatPolicies(BitmaskToPolicies(fulfilled_policies)).c_str(),
+ ConcatPolicies(BitmaskToPolicies(overlayable_info->policy_flags)).c_str());
+ }
+
+ return Result<Unit>({});
+}
+
+// TODO(martenkongstad): scan for package name instead of assuming package at index 0
+//
+// idmap version 0x01 naively assumes that the package to use is always the first ResTable_package
+// in the resources.arsc blob. In most cases, there is only a single ResTable_package anyway, so
+// this assumption tends to work out. That said, the correct thing to do is to scan
+// resources.arsc for a package with a given name as read from the package manifest instead of
+// relying on a hard-coded index. This however requires storing the package name in the idmap
+// header, which in turn requires incrementing the idmap version. Because the initial version of
+// idmap2 is compatible with idmap, this will have to wait for now.
+const LoadedPackage* GetPackageAtIndex0(const LoadedArsc& loaded_arsc) {
+ const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc.GetPackages();
+ if (packages.empty()) {
+ return nullptr;
+ }
+ int id = packages[0]->GetPackageId();
+ return loaded_arsc.GetPackageById(id);
+}
+
+Result<std::unique_ptr<Asset>> OpenNonAssetFromResource(const ResourceId& resource_id,
+ const AssetManager2& asset_manager) {
+ Res_value value{};
+ ResTable_config selected_config{};
+ uint32_t flags;
+ auto cookie =
+ asset_manager.GetResource(resource_id, /* may_be_bag */ false,
+ /* density_override */ 0U, &value, &selected_config, &flags);
+ if (cookie == kInvalidCookie) {
+ return Error("failed to find resource for id 0x%08x", resource_id);
+ }
+
+ if (value.dataType != Res_value::TYPE_STRING) {
+ return Error("resource for is 0x%08x is not a file", resource_id);
+ }
+
+ auto string_pool = asset_manager.GetStringPoolForCookie(cookie);
+ size_t len;
+ auto file_path16 = string_pool->stringAt(value.data, &len);
+ if (file_path16 == nullptr) {
+ return Error("failed to find string for index %d", value.data);
+ }
+
+ // Load the overlay resource mappings from the file specified using android:resourcesMap.
+ auto file_path = String8(String16(file_path16));
+ auto asset = asset_manager.OpenNonAsset(file_path.c_str(), Asset::AccessMode::ACCESS_BUFFER);
+ if (asset == nullptr) {
+ return Error("file \"%s\" not found", file_path.c_str());
+ }
+
+ return asset;
+}
+
+} // namespace
+
+Result<ResourceMapping> ResourceMapping::CreateResourceMapping(const AssetManager2* target_am,
+ const LoadedPackage* target_package,
+ const LoadedPackage* overlay_package,
+ size_t string_pool_offset,
+ const XmlParser& overlay_parser) {
+ ResourceMapping resource_mapping;
+ auto root_it = overlay_parser.tree_iterator();
+ if (root_it->event() != XmlParser::Event::START_TAG || root_it->name() != "overlay") {
+ return Error("root element is not <overlay> tag");
+ }
+
+ const uint8_t overlay_package_id = overlay_package->GetPackageId();
+ auto overlay_it_end = root_it.end();
+ for (auto overlay_it = root_it.begin(); overlay_it != overlay_it_end; ++overlay_it) {
+ if (overlay_it->event() == XmlParser::Event::BAD_DOCUMENT) {
+ return Error("failed to parse overlay xml document");
+ }
+
+ if (overlay_it->event() != XmlParser::Event::START_TAG) {
+ continue;
+ }
+
+ if (overlay_it->name() != "item") {
+ return Error("unexpected tag <%s> in <overlay>", overlay_it->name().c_str());
+ }
+
+ Result<std::string> target_resource = overlay_it->GetAttributeStringValue("target");
+ if (!target_resource) {
+ return Error(R"(<item> tag missing expected attribute "target")");
+ }
+
+ Result<android::Res_value> overlay_resource = overlay_it->GetAttributeValue("value");
+ if (!overlay_resource) {
+ return Error(R"(<item> tag missing expected attribute "value")");
+ }
+
+ ResourceId target_id =
+ target_am->GetResourceId(*target_resource, "", target_package->GetPackageName());
+ if (target_id == 0U) {
+ LOG(WARNING) << "failed to find resource \"" << *target_resource << "\" in target resources";
+ continue;
+ }
+
+ if (overlay_resource->dataType == Res_value::TYPE_STRING) {
+ overlay_resource->data += string_pool_offset;
+ }
+
+ // Only rewrite resources defined within the overlay package to their corresponding target
+ // resource ids at runtime.
+ bool rewrite_overlay_reference =
+ (overlay_resource->dataType == Res_value::TYPE_REFERENCE)
+ ? overlay_package_id == EXTRACT_PACKAGE(overlay_resource->data)
+ : false;
+
+ resource_mapping.AddMapping(target_id, overlay_resource->dataType, overlay_resource->data,
+ rewrite_overlay_reference);
+ }
+
+ return resource_mapping;
+}
+
+Result<ResourceMapping> ResourceMapping::CreateResourceMappingLegacy(
+ const AssetManager2* target_am, const AssetManager2* overlay_am,
+ const LoadedPackage* target_package, const LoadedPackage* overlay_package) {
+ ResourceMapping resource_mapping;
+ const auto end = overlay_package->end();
+ for (auto iter = overlay_package->begin(); iter != end; ++iter) {
+ const ResourceId overlay_resid = *iter;
+ Result<std::string> name = utils::ResToTypeEntryName(*overlay_am, overlay_resid);
+ if (!name) {
+ continue;
+ }
+
+ // Find the resource with the same type and entry name within the target package.
+ const std::string full_name =
+ base::StringPrintf("%s:%s", target_package->GetPackageName().c_str(), name->c_str());
+ const ResourceId target_resource = target_am->GetResourceId(full_name);
+ if (target_resource == 0U) {
+ continue;
+ }
+
+ resource_mapping.AddMapping(target_resource, Res_value::TYPE_REFERENCE, overlay_resid,
+ /* rewrite_overlay_reference */ true);
+ }
+
+ return resource_mapping;
+}
+
+void ResourceMapping::FilterOverlayableResources(const AssetManager2* target_am,
+ const LoadedPackage* target_package,
+ const LoadedPackage* overlay_package,
+ const OverlayManifestInfo& overlay_info,
+ const PolicyBitmask& fulfilled_policies) {
+ std::set<ResourceId> remove_ids;
+ for (const auto& target_map : target_map_) {
+ const ResourceId target_resid = target_map.first;
+ Result<Unit> success =
+ CheckOverlayable(*target_package, overlay_info, fulfilled_policies, target_resid);
+ if (success) {
+ continue;
+ }
+
+ // Attempting to overlay a resource that is not allowed to be overlaid is treated as a
+ // warning.
+ Result<std::string> name = utils::ResToTypeEntryName(*target_am, target_resid);
+ if (!name) {
+ name = StringPrintf("0x%08x", target_resid);
+ }
+
+ LOG(WARNING) << "overlay \"" << overlay_package->GetPackageName()
+ << "\" is not allowed to overlay resource \"" << *name
+ << "\" in target: " << success.GetErrorMessage();
+
+ remove_ids.insert(target_resid);
+ }
+
+ for (const ResourceId target_resid : remove_ids) {
+ RemoveMapping(target_resid);
+ }
+}
+
+Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_apk_assets,
+ const ApkAssets& overlay_apk_assets,
+ const OverlayManifestInfo& overlay_info,
+ const PolicyBitmask& fulfilled_policies,
+ bool enforce_overlayable) {
+ AssetManager2 target_asset_manager;
+ if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true /* invalidate_caches */,
+ false /* filter_incompatible_configs*/)) {
+ return Error("failed to create target asset manager");
+ }
+
+ AssetManager2 overlay_asset_manager;
+ if (!overlay_asset_manager.SetApkAssets({&overlay_apk_assets}, true /* invalidate_caches */,
+ false /* filter_incompatible_configs */)) {
+ return Error("failed to create overlay asset manager");
+ }
+
+ const LoadedArsc* target_arsc = target_apk_assets.GetLoadedArsc();
+ if (target_arsc == nullptr) {
+ return Error("failed to load target resources.arsc");
+ }
+
+ const LoadedArsc* overlay_arsc = overlay_apk_assets.GetLoadedArsc();
+ if (overlay_arsc == nullptr) {
+ return Error("failed to load overlay resources.arsc");
+ }
+
+ const LoadedPackage* target_pkg = GetPackageAtIndex0(*target_arsc);
+ if (target_pkg == nullptr) {
+ return Error("failed to load target package from resources.arsc");
+ }
+
+ const LoadedPackage* overlay_pkg = GetPackageAtIndex0(*overlay_arsc);
+ if (overlay_pkg == nullptr) {
+ return Error("failed to load overlay package from resources.arsc");
+ }
+
+ size_t string_pool_data_length = 0U;
+ size_t string_pool_offset = 0U;
+ std::unique_ptr<uint8_t[]> string_pool_data;
+ Result<ResourceMapping> resource_mapping = {{}};
+ if (overlay_info.resource_mapping != 0U) {
+ // Load the overlay resource mappings from the file specified using android:resourcesMap.
+ auto asset = OpenNonAssetFromResource(overlay_info.resource_mapping, overlay_asset_manager);
+ if (!asset) {
+ return Error("failed opening xml for android:resourcesMap: %s",
+ asset.GetErrorMessage().c_str());
+ }
+
+ auto parser =
+ XmlParser::Create((*asset)->getBuffer(true /* wordAligned*/), (*asset)->getLength());
+ if (!parser) {
+ return Error("failed opening ResXMLTree");
+ }
+
+ // Copy the xml string pool data before the parse goes out of scope.
+ auto& string_pool = (*parser)->get_strings();
+ string_pool_data_length = string_pool.bytes();
+ string_pool_data.reset(new uint8_t[string_pool_data_length]);
+ memcpy(string_pool_data.get(), string_pool.data(), string_pool_data_length);
+
+ // Offset string indices by the size of the overlay resource table string pool.
+ string_pool_offset = overlay_arsc->GetStringPool()->size();
+
+ resource_mapping = CreateResourceMapping(&target_asset_manager, target_pkg, overlay_pkg,
+ string_pool_offset, *(*parser));
+ } else {
+ // If no file is specified using android:resourcesMap, it is assumed that the overlay only
+ // defines resources intended to override target resources of the same type and name.
+ resource_mapping = CreateResourceMappingLegacy(&target_asset_manager, &overlay_asset_manager,
+ target_pkg, overlay_pkg);
+ }
+
+ if (!resource_mapping) {
+ return resource_mapping.GetError();
+ }
+
+ if (enforce_overlayable) {
+ // Filter out resources the overlay is not allowed to override.
+ (*resource_mapping)
+ .FilterOverlayableResources(&target_asset_manager, target_pkg, overlay_pkg, overlay_info,
+ fulfilled_policies);
+ }
+
+ resource_mapping->target_package_id_ = target_pkg->GetPackageId();
+ resource_mapping->overlay_package_id_ = overlay_pkg->GetPackageId();
+ resource_mapping->string_pool_offset_ = string_pool_offset;
+ resource_mapping->string_pool_data_ = std::move(string_pool_data);
+ resource_mapping->string_pool_data_length_ = string_pool_data_length;
+ return std::move(*resource_mapping);
+}
+
+OverlayResourceMap ResourceMapping::GetOverlayToTargetMap() const {
+ // An overlay resource can override multiple target resources at once. Rewrite the overlay
+ // resource as the first target resource it overrides.
+ OverlayResourceMap map;
+ for (const auto& mappings : overlay_map_) {
+ map.insert(std::make_pair(mappings.first, mappings.second));
+ }
+ return map;
+}
+
+Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource,
+ TargetValue::DataType data_type,
+ TargetValue::DataValue data_value,
+ bool rewrite_overlay_reference) {
+ if (target_map_.find(target_resource) != target_map_.end()) {
+ return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
+ }
+
+ // TODO(141485591): Ensure that the overlay type is compatible with the target type. If the
+ // runtime types are not compatible, it could cause runtime crashes when the resource is resolved.
+
+ target_map_.insert(std::make_pair(target_resource, TargetValue{data_type, data_value}));
+
+ if (rewrite_overlay_reference && data_type == Res_value::TYPE_REFERENCE) {
+ overlay_map_.insert(std::make_pair(data_value, target_resource));
+ }
+
+ return Result<Unit>({});
+}
+
+void ResourceMapping::RemoveMapping(ResourceId target_resource) {
+ auto target_iter = target_map_.find(target_resource);
+ if (target_iter == target_map_.end()) {
+ return;
+ }
+
+ const TargetValue value = target_iter->second;
+ target_map_.erase(target_iter);
+
+ // Remove rewriting of overlay resource id to target resource id.
+ if (value.data_type != Res_value::TYPE_REFERENCE) {
+ return;
+ }
+
+ auto overlay_iter = overlay_map_.equal_range(value.data_value);
+ for (auto i = overlay_iter.first; i != overlay_iter.second; ++i) {
+ if (i->second == target_resource) {
+ overlay_map_.erase(i);
+ return;
+ }
+ }
+}
+
+} // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp
index dce83e35978d..9d3269207c91 100644
--- a/cmds/idmap2/libidmap2/ResourceUtils.cpp
+++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp
@@ -22,18 +22,18 @@
#include "androidfw/StringPiece.h"
#include "androidfw/Util.h"
#include "idmap2/Result.h"
-#include "idmap2/Xml.h"
+#include "idmap2/XmlParser.h"
#include "idmap2/ZipFile.h"
using android::StringPiece16;
using android::idmap2::Result;
-using android::idmap2::Xml;
+using android::idmap2::XmlParser;
using android::idmap2::ZipFile;
using android::util::Utf16ToUtf8;
namespace android::idmap2::utils {
-Result<std::string> ResToTypeEntryName(const AssetManager2& am, ResourceId resid) {
+Result<std::string> ResToTypeEntryName(const AssetManager2& am, uint32_t resid) {
AssetManager2::ResourceName name;
if (!am.GetResourceName(resid, &name)) {
return Error("no resource 0x%08x in asset manager", resid);
@@ -65,52 +65,72 @@ Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
return Error("failed to uncompress AndroidManifest.xml from %s", path.c_str());
}
- std::unique_ptr<const Xml> xml = Xml::Create(entry->buf, entry->size);
+ Result<std::unique_ptr<const XmlParser>> xml = XmlParser::Create(entry->buf, entry->size);
if (!xml) {
return Error("failed to parse AndroidManifest.xml from %s", path.c_str());
}
+ auto manifest_it = (*xml)->tree_iterator();
+ if (manifest_it->event() != XmlParser::Event::START_TAG || manifest_it->name() != "manifest") {
+ return Error("root element tag is not <manifest> in AndroidManifest.xml of %s", path.c_str());
+ }
+
+ auto overlay_it = std::find_if(manifest_it.begin(), manifest_it.end(), [](const auto& it) {
+ return it.event() == XmlParser::Event::START_TAG && it.name() == "overlay";
+ });
+
OverlayManifestInfo info{};
- const auto tag = xml->FindTag("overlay");
- if (!tag) {
- if (assert_overlay) {
- return Error("<overlay> missing from AndroidManifest.xml of %s", path.c_str());
+ if (overlay_it == manifest_it.end()) {
+ if (!assert_overlay) {
+ return info;
}
- return info;
+ return Error("<overlay> missing from AndroidManifest.xml of %s", path.c_str());
}
- auto iter = tag->find("targetPackage");
- if (iter == tag->end()) {
- if (assert_overlay) {
- return Error("android:targetPackage missing from <overlay> of %s", path.c_str());
- }
+ if (auto result_str = overlay_it->GetAttributeStringValue("targetPackage")) {
+ info.target_package = *result_str;
} else {
- info.target_package = iter->second;
+ return Error("android:targetPackage missing from <overlay> of %s: %s", path.c_str(),
+ result_str.GetErrorMessage().c_str());
}
- iter = tag->find("targetName");
- if (iter != tag->end()) {
- info.target_name = iter->second;
+ if (auto result_str = overlay_it->GetAttributeStringValue("targetName")) {
+ info.target_name = *result_str;
}
- iter = tag->find("isStatic");
- if (iter != tag->end()) {
- info.is_static = std::stoul(iter->second) != 0U;
+ if (auto result_value = overlay_it->GetAttributeValue("resourcesMap")) {
+ if ((*result_value).dataType == Res_value::TYPE_REFERENCE) {
+ info.resource_mapping = (*result_value).data;
+ } else {
+ return Error("android:resourcesMap is not a reference in AndroidManifest.xml of %s",
+ path.c_str());
+ }
}
- iter = tag->find("priority");
- if (iter != tag->end()) {
- info.priority = std::stoi(iter->second);
+ if (auto result_value = overlay_it->GetAttributeValue("isStatic")) {
+ if ((*result_value).dataType >= Res_value::TYPE_FIRST_INT &&
+ (*result_value).dataType <= Res_value::TYPE_LAST_INT) {
+ info.is_static = (*result_value).data != 0U;
+ } else {
+ return Error("android:isStatic is not a boolean in AndroidManifest.xml of %s", path.c_str());
+ }
+ }
+
+ if (auto result_value = overlay_it->GetAttributeValue("priority")) {
+ if ((*result_value).dataType >= Res_value::TYPE_FIRST_INT &&
+ (*result_value).dataType <= Res_value::TYPE_LAST_INT) {
+ info.priority = (*result_value).data;
+ } else {
+ return Error("android:priority is not an integer in AndroidManifest.xml of %s", path.c_str());
+ }
}
- iter = tag->find("requiredSystemPropertyName");
- if (iter != tag->end()) {
- info.requiredSystemPropertyName = iter->second;
+ if (auto result_str = overlay_it->GetAttributeStringValue("requiredSystemPropertyName")) {
+ info.requiredSystemPropertyName = *result_str;
}
- iter = tag->find("requiredSystemPropertyValue");
- if (iter != tag->end()) {
- info.requiredSystemPropertyValue = iter->second;
+ if (auto result_str = overlay_it->GetAttributeStringValue("requiredSystemPropertyValue")) {
+ info.requiredSystemPropertyValue = *result_str;
}
return info;
diff --git a/cmds/idmap2/libidmap2/Xml.cpp b/cmds/idmap2/libidmap2/Xml.cpp
deleted file mode 100644
index 264586829c47..000000000000
--- a/cmds/idmap2/libidmap2/Xml.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2018 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 "idmap2/Xml.h"
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-
-namespace android::idmap2 {
-
-std::unique_ptr<const Xml> Xml::Create(const uint8_t* data, size_t size, bool copyData) {
- std::unique_ptr<Xml> xml(new Xml());
- if (xml->xml_.setTo(data, size, copyData) != NO_ERROR) {
- return nullptr;
- }
- return xml;
-}
-
-std::unique_ptr<std::map<std::string, std::string>> Xml::FindTag(const std::string& name) const {
- const String16 tag_to_find(name.c_str(), name.size());
- xml_.restart();
- ResXMLParser::event_code_t type;
- do {
- type = xml_.next();
- if (type == ResXMLParser::START_TAG) {
- size_t len;
- const String16 tag(xml_.getElementName(&len));
- if (tag == tag_to_find) {
- std::unique_ptr<std::map<std::string, std::string>> map(
- new std::map<std::string, std::string>());
- for (size_t i = 0; i < xml_.getAttributeCount(); i++) {
- const String16 key16(xml_.getAttributeName(i, &len));
- std::string key = String8(key16).c_str();
-
- std::string value;
- switch (xml_.getAttributeDataType(i)) {
- case Res_value::TYPE_STRING: {
- const String16 value16(xml_.getAttributeStringValue(i, &len));
- value = String8(value16).c_str();
- } break;
- case Res_value::TYPE_INT_DEC:
- case Res_value::TYPE_INT_HEX:
- case Res_value::TYPE_INT_BOOLEAN: {
- Res_value resValue;
- xml_.getAttributeValue(i, &resValue);
- value = std::to_string(resValue.data);
- } break;
- default:
- return nullptr;
- }
-
- map->emplace(std::make_pair(key, value));
- }
- return map;
- }
- }
- } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT);
- return nullptr;
-}
-
-Xml::~Xml() {
- xml_.uninit();
-}
-
-} // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
new file mode 100644
index 000000000000..526a560907aa
--- /dev/null
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -0,0 +1,163 @@
+/*
+ * 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 "idmap2/XmlParser.h"
+
+#include <iostream>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace android::idmap2 {
+
+template <typename T>
+ResXMLParser::ResXMLPosition get_tree_position(const T& tree) {
+ ResXMLParser::ResXMLPosition pos{};
+ tree.getPosition(&pos);
+ return pos;
+}
+
+XmlParser::Node::Node(const ResXMLTree& tree) : Node(tree, get_tree_position(tree)) {
+}
+XmlParser::Node::Node(const ResXMLTree& tree, const ResXMLParser::ResXMLPosition& pos)
+ : parser_(tree) {
+ set_position(pos);
+}
+
+bool XmlParser::Node::operator==(const XmlParser::Node& rhs) const {
+ ResXMLParser::ResXMLPosition pos = get_position();
+ ResXMLParser::ResXMLPosition rhs_pos = rhs.get_position();
+ return pos.curExt == rhs_pos.curExt && pos.curNode == rhs_pos.curNode &&
+ pos.eventCode == rhs_pos.eventCode;
+}
+
+bool XmlParser::Node::operator!=(const XmlParser::Node& rhs) const {
+ return !(*this == rhs);
+}
+
+ResXMLParser::ResXMLPosition XmlParser::Node::get_position() const {
+ return get_tree_position(parser_);
+}
+
+void XmlParser::Node::set_position(const ResXMLParser::ResXMLPosition& pos) {
+ parser_.setPosition(pos);
+}
+
+bool XmlParser::Node::Seek(bool inner_child) {
+ if (parser_.getEventType() == XmlParser::Event::END_TAG) {
+ return false;
+ }
+
+ ssize_t depth = 0;
+ XmlParser::Event code;
+ while ((code = parser_.next()) != XmlParser::Event::BAD_DOCUMENT &&
+ code != XmlParser::Event::END_DOCUMENT) {
+ if (code == XmlParser::Event::START_TAG) {
+ if (++depth == (inner_child ? 1 : 0)) {
+ return true;
+ }
+ } else if (code == XmlParser::Event::END_TAG) {
+ if (--depth == (inner_child ? -1 : -2)) {
+ return false;
+ }
+ }
+ }
+
+ return false;
+}
+
+XmlParser::Event XmlParser::Node::event() const {
+ return parser_.getEventType();
+}
+
+std::string XmlParser::Node::name() const {
+ size_t len;
+ const String16 key16(parser_.getElementName(&len));
+ return String8(key16).c_str();
+}
+
+Result<std::string> XmlParser::Node::GetAttributeStringValue(const std::string& name) const {
+ auto value = GetAttributeValue(name);
+ if (!value) {
+ return value.GetError();
+ }
+
+ switch ((*value).dataType) {
+ case Res_value::TYPE_STRING: {
+ size_t len;
+ const String16 value16(parser_.getStrings().stringAt((*value).data, &len));
+ return std::string(String8(value16).c_str());
+ }
+ case Res_value::TYPE_INT_DEC:
+ case Res_value::TYPE_INT_HEX:
+ case Res_value::TYPE_INT_BOOLEAN: {
+ return std::to_string((*value).data);
+ }
+ default:
+ return Error(R"(Failed to convert attribute "%s" value to a string)", name.c_str());
+ }
+}
+
+Result<Res_value> XmlParser::Node::GetAttributeValue(const std::string& name) const {
+ size_t len;
+ for (size_t i = 0; i < parser_.getAttributeCount(); i++) {
+ const String16 key16(parser_.getAttributeName(i, &len));
+ std::string key = String8(key16).c_str();
+ if (key != name) {
+ continue;
+ }
+
+ Res_value res_value{};
+ if (parser_.getAttributeValue(i, &res_value) == BAD_TYPE) {
+ return Error(R"(Bad value for attribute "%s")", name.c_str());
+ }
+
+ return res_value;
+ }
+
+ return Error(R"(Failed to find attribute "%s")", name.c_str());
+}
+
+Result<std::unique_ptr<const XmlParser>> XmlParser::Create(const void* data, size_t size,
+ bool copy_data) {
+ auto parser = std::unique_ptr<const XmlParser>(new XmlParser());
+ if (parser->tree_.setTo(data, size, copy_data) != NO_ERROR) {
+ return Error("Malformed xml block");
+ }
+
+ // Find the beginning of the first tag.
+ XmlParser::Event event;
+ while ((event = parser->tree_.next()) != XmlParser::Event::BAD_DOCUMENT &&
+ event != XmlParser::Event::END_DOCUMENT && event != XmlParser::Event::START_TAG) {
+ }
+
+ if (event == XmlParser::Event::END_DOCUMENT) {
+ return Error("Root tag was not be found");
+ }
+
+ if (event == XmlParser::Event::BAD_DOCUMENT) {
+ return Error("Bad xml document");
+ }
+
+ return parser;
+}
+
+XmlParser::~XmlParser() {
+ tree_.uninit();
+}
+
+} // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/ZipFile.cpp b/cmds/idmap2/libidmap2/ZipFile.cpp
index 4f5e3a45f183..1e1a218163f0 100644
--- a/cmds/idmap2/libidmap2/ZipFile.cpp
+++ b/cmds/idmap2/libidmap2/ZipFile.cpp
@@ -34,6 +34,7 @@ std::unique_ptr<const ZipFile> ZipFile::Open(const std::string& path) {
::ZipArchiveHandle handle;
int32_t status = ::OpenArchive(path.c_str(), &handle);
if (status != 0) {
+ ::CloseArchive(handle);
return nullptr;
}
return std::unique_ptr<ZipFile>(new ZipFile(handle));
diff --git a/cmds/idmap2/static-checks.sh b/cmds/idmap2/static-checks.sh
index 41d3c69540b2..a372abdaa146 100755
--- a/cmds/idmap2/static-checks.sh
+++ b/cmds/idmap2/static-checks.sh
@@ -27,10 +27,11 @@ function _eval()
local red="\e[31m"
local green="\e[32m"
local reset="\e[0m"
+ local output
_log "${green}[ RUN ]${reset} ${label}"
- local output="$(eval "$cmd")"
- if [[ -z "${output}" ]]; then
+ output="$(eval "$cmd" 2>&1)"
+ if [[ $? -eq 0 ]]; then
_log "${green}[ OK ]${reset} ${label}"
return 0
else
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 9348ab721493..43fdc9a78186 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -75,9 +75,8 @@ TEST(BinaryStreamVisitorTests, CreateIdmapFromApkAssetsInteropWithLoadedIdmap) {
std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
ASSERT_THAT(overlay_apk, NotNull());
- const auto idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true);
+ const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true);
ASSERT_TRUE(idmap);
std::stringstream stream;
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 0f47f1e77d7b..47e5b17f4a98 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -179,8 +179,7 @@ void CreateIdmap(const StringPiece& target_apk_path, const StringPiece& overlay_
ASSERT_THAT(overlay_apk, NotNull());
auto result =
- Idmap::FromApkAssets(target_apk_path.to_string(), *target_apk, overlay_apk_path.to_string(),
- *overlay_apk, fulfilled_policies, enforce_overlayable);
+ Idmap::FromApkAssets(*target_apk, *overlay_apk, fulfilled_policies, enforce_overlayable);
*out_idmap = result ? std::move(*result) : nullptr;
}
@@ -195,7 +194,7 @@ TEST(IdmapTests, CreateIdmapFromApkAssets) {
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x76a20829);
- ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x8635c2ed);
+ ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xc054fb26);
ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
@@ -480,9 +479,8 @@ TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
ASSERT_THAT(overlay_apk, NotNull());
- const auto result =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true);
+ const auto result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true);
ASSERT_FALSE(result);
}
@@ -497,8 +495,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
ASSERT_THAT(overlay_apk, NotNull());
- auto result = Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_PUBLIC,
+ auto result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
/* enforce_overlayable */ true);
ASSERT_TRUE(result);
const auto idmap = std::move(*result);
diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
index c41250457678..1d34e42e188d 100644
--- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
@@ -43,9 +43,8 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitor) {
std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
ASSERT_THAT(overlay_apk, NotNull());
- const auto idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true);
+ const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true);
ASSERT_TRUE(idmap);
std::stringstream stream;
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 26951763cd66..c243d745e568 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -38,9 +38,8 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
ASSERT_THAT(overlay_apk, NotNull());
- const auto idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true);
+ const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true);
ASSERT_TRUE(idmap);
std::stringstream stream;
@@ -50,7 +49,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos);
ASSERT_NE(stream.str().find("00000004: 00000001 version\n"), std::string::npos);
ASSERT_NE(stream.str().find("00000008: 76a20829 target crc\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000000c: 8635c2ed overlay crc\n"), std::string::npos);
+ ASSERT_NE(stream.str().find("0000000c: c054fb26 overlay crc\n"), std::string::npos);
ASSERT_NE(stream.str().find("0000021c: 00000000 0x7f010000 -> 0x7f010000 integer/int1\n"),
std::string::npos);
}
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
new file mode 100644
index 000000000000..1ef41de4410d
--- /dev/null
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2018 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 <cstdio> // fclose
+#include <fstream>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "TestHelpers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "idmap2/ResourceMapping.h"
+
+using android::idmap2::utils::ExtractOverlayManifestInfo;
+
+namespace android::idmap2 {
+
+#define ASSERT_RESULT(r) \
+ do { \
+ auto result = r; \
+ ASSERT_TRUE(result) << result.GetErrorMessage(); \
+ } while (0)
+
+Result<ResourceMapping> TestGetResourceMapping(const android::StringPiece& local_target_apk_path,
+ const android::StringPiece& local_overlay_apk_path,
+ const OverlayManifestInfo& overlay_info,
+ const PolicyBitmask& fulfilled_policies,
+ bool enforce_overlayable) {
+ const std::string target_apk_path(GetTestDataPath() + local_target_apk_path.data());
+ std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+ if (!target_apk) {
+ return Error(R"(Failed to load target apk "%s")", target_apk_path.data());
+ }
+
+ const std::string overlay_apk_path(GetTestDataPath() + local_overlay_apk_path.data());
+ std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+ if (!overlay_apk) {
+ return Error(R"(Failed to load overlay apk "%s")", overlay_apk_path.data());
+ }
+
+ return ResourceMapping::FromApkAssets(*target_apk, *overlay_apk, overlay_info, fulfilled_policies,
+ enforce_overlayable);
+}
+
+Result<ResourceMapping> TestGetResourceMapping(const android::StringPiece& local_target_apk_path,
+ const android::StringPiece& local_overlay_apk_path,
+ const PolicyBitmask& fulfilled_policies,
+ bool enforce_overlayable) {
+ auto overlay_info = ExtractOverlayManifestInfo(GetTestDataPath() + local_overlay_apk_path.data());
+ if (!overlay_info) {
+ return overlay_info.GetError();
+ }
+ return TestGetResourceMapping(local_target_apk_path, local_overlay_apk_path, *overlay_info,
+ fulfilled_policies, enforce_overlayable);
+}
+
+Result<Unit> MappingExists(const ResourceMapping& mapping, const ResourceId& target_resource,
+ const uint8_t type, const uint32_t value, bool rewrite) {
+ auto target_map = mapping.GetTargetToOverlayMap();
+ auto entry_map = target_map.find(target_resource);
+ if (entry_map == target_map.end()) {
+ return Error("Failed to find mapping for target resource");
+ }
+
+ if (entry_map->second.data_type != type) {
+ return Error(R"(Expected type: "0x%02x" Actual type: "0x%02x")", type,
+ entry_map->second.data_type);
+ }
+
+ if (entry_map->second.data_value != value) {
+ return Error(R"(Expected value: "0x%08x" Actual value: "0x%08x")", type,
+ entry_map->second.data_value);
+ }
+
+ auto overlay_map = mapping.GetOverlayToTargetMap();
+ auto overlay_iter = overlay_map.find(entry_map->second.data_value);
+ if ((overlay_iter != overlay_map.end()) != rewrite) {
+ return Error(R"(Expected rewriting: "%s")", rewrite ? "true" : "false");
+ }
+
+ return Result<Unit>({});
+}
+
+TEST(ResourceMappingTests, ResourcesFromApkAssetsLegacy) {
+ OverlayManifestInfo info{};
+ info.target_package = "test.target";
+ info.target_name = "TestResources";
+ info.resource_mapping = 0U; // no xml
+ auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
+ PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ false);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
+ ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
+ true /* rewrite */)); // integer/int1
+ ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000,
+ true /* rewrite */)); // string/str1
+ ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
+ true /* rewrite */)); // string/str3
+ ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002,
+ true /* rewrite */)); // string/str4
+}
+
+TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
+ OverlayManifestInfo info{};
+ info.target_package = "test.target";
+ info.target_name = "TestResources";
+ info.resource_mapping = 0x7f030003; // xml/overlays_swap
+ auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
+ PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ false);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
+ ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002,
+ true /* rewrite */)); // string/str1 -> string/str4
+ ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000,
+ true /* rewrite */)); // string/str3 -> string/str1
+ ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
+ true /* rewrite */)); // string/str4 -> string/str3
+}
+
+TEST(ResourceMappingTests, DoNotRewriteNonResourceMapping) {
+ OverlayManifestInfo info{};
+ info.target_package = "test.target";
+ info.target_name = "TestResources";
+ info.resource_mapping = 0x7f030001; // xml/overlays_different_packages
+ auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
+ PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ false);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
+ ASSERT_EQ(res.GetOverlayToTargetMap().size(), 1U);
+ ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x0104000a,
+ false /* rewrite */)); // string/str1 -> android:string/ok
+ ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
+ true /* rewrite */)); // string/str3 -> string/str4
+}
+
+TEST(ResourceMappingTests, InlineResources) {
+ OverlayManifestInfo info{};
+ info.target_package = "test.target";
+ info.target_name = "TestResources";
+ info.resource_mapping = 0x7f030002; // xml/overlays_inline
+ auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
+ PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ false);
+
+ constexpr size_t overlay_string_pool_size = 8U;
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
+ ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
+ ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x03 /* Res_value::TYPE_STRING */,
+ overlay_string_pool_size + 0U,
+ false /* rewrite */)); // string/str1 -> "Hello World"
+ ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x10 /* Res_value::TYPE_INT_DEC */, 73U,
+ false /* rewrite */)); // string/str1 -> "Hello World"
+}
+
+TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
+ auto resources =
+ TestGetResourceMapping("/target/target.apk", "/system-overlay/system-overlay.apk",
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
+ ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
+ true /* rewrite */)); // string/policy_public
+ ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001,
+ true /* rewrite */)); // string/policy_system
+ ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002,
+ true /* rewrite */)); // string/policy_system_vendor
+}
+
+// Resources that are not declared as overlayable and resources that a protected by policies the
+// overlay does not fulfill must not map to overlay resources.
+TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
+ auto resources = TestGetResourceMapping(
+ "/target/target.apk", "/system-overlay-invalid/system-overlay-invalid.apk",
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
+ ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005,
+ true /* rewrite */)); // string/policy_public
+ ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007,
+ true /* rewrite */)); // string/policy_system
+ ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008,
+ true /* rewrite */)); // string/policy_system_vendor
+}
+
+// Resources that are not declared as overlayable and resources that a protected by policies the
+// overlay does not fulfilled can map to overlay resources when overlayable enforcement is turned
+// off.
+TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
+ auto resources = TestGetResourceMapping(
+ "/target/target.apk", "/system-overlay-invalid/system-overlay-invalid.apk",
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ false);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 9U);
+ ASSERT_RESULT(MappingExists(res, 0x7f020003, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
+ true /* rewrite */)); // string/not_overlayable
+ ASSERT_RESULT(MappingExists(res, 0x7f020004, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001,
+ true /* rewrite */)); // string/other
+ ASSERT_RESULT(MappingExists(res, 0x7f020005, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002,
+ true /* rewrite */)); // string/policy_odm
+ ASSERT_RESULT(MappingExists(res, 0x7f020006, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010003,
+ true /* rewrite */)); // string/policy_oem
+ ASSERT_RESULT(MappingExists(res, 0x7f020007, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010004,
+ true /* rewrite */)); // string/policy_product
+ ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005,
+ true /* rewrite */)); // string/policy_public
+ ASSERT_RESULT(MappingExists(res, 0x7f020009, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010006,
+ true /* rewrite */)); // string/policy_signature
+ ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007,
+ true /* rewrite */)); // string/policy_system
+ ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008,
+ true /* rewrite */)); // string/policy_system_vendor
+}
+
+// Overlays that do not target an <overlayable> tag can overlay resources defined within any
+// <overlayable> tag.
+TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTargetName) {
+ auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay-no-name.apk",
+ PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ false);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
+ ASSERT_RESULT(MappingExists(res, 0x7f010000, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
+ true /* rewrite */)); // integer/int1
+ ASSERT_RESULT(MappingExists(res, 0x7f02000c, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020000,
+ true /* rewrite */)); // string/str1
+ ASSERT_RESULT(MappingExists(res, 0x7f02000e, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020001,
+ true /* rewrite */)); // string/str3
+ ASSERT_RESULT(MappingExists(res, 0x7f02000f, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f020002,
+ true /* rewrite */)); // string/str4
+}
+
+// Overlays that are neither pre-installed nor signed with the same signature as the target cannot
+// overlay packages that have not defined overlayable resources.
+TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
+ auto resources =
+ TestGetResourceMapping("/target/target-no-overlayable.apk", "/overlay/overlay-no-name.apk",
+ PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
+}
+
+// Overlays that are pre-installed or are signed with the same signature as the target can overlay
+// packages that have not defined overlayable resources.
+TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
+ auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
+ auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
+ "/system-overlay-invalid/system-overlay-invalid.apk",
+ fulfilled_policies,
+ /* enforce_overlayable */ true);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 9U);
+ ASSERT_RESULT(MappingExists(res, 0x7f020003, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010000,
+ true /* rewrite */)); // string/not_overlayable
+ ASSERT_RESULT(MappingExists(res, 0x7f020004, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010001,
+ true /* rewrite */)); // string/other
+ ASSERT_RESULT(MappingExists(res, 0x7f020005, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010002,
+ true /* rewrite */)); // string/policy_odm
+ ASSERT_RESULT(MappingExists(res, 0x7f020006, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010003,
+ true /* rewrite */)); // string/policy_oem
+ ASSERT_RESULT(MappingExists(res, 0x7f020007, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010004,
+ true /* rewrite */)); // string/policy_product
+ ASSERT_RESULT(MappingExists(res, 0x7f020008, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010005,
+ true /* rewrite */)); // string/policy_public
+ ASSERT_RESULT(MappingExists(res, 0x7f020009, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010006,
+ true /* rewrite */)); // string/policy_signature
+ ASSERT_RESULT(MappingExists(res, 0x7f02000a, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010007,
+ true /* rewrite */)); // string/policy_system
+ ASSERT_RESULT(MappingExists(res, 0x7f02000b, 0x01 /* Res_value::TYPE_REFERENCE */, 0x7f010008,
+ true /* rewrite */)); // string/policy_system_vendor
+ };
+
+ CheckEntries(PolicyFlags::POLICY_SIGNATURE);
+ CheckEntries(PolicyFlags::POLICY_PRODUCT_PARTITION);
+ CheckEntries(PolicyFlags::POLICY_SYSTEM_PARTITION);
+ CheckEntries(PolicyFlags::POLICY_VENDOR_PARTITION);
+ CheckEntries(PolicyFlags::POLICY_ODM_PARTITION);
+ CheckEntries(PolicyFlags::POLICY_OEM_PARTITION);
+}
+
+} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index adea3293534d..a7c2f284e7c5 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -123,7 +123,7 @@ std::string GetTestDataPath();
class Idmap2Tests : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
#ifdef __ANDROID__
tmp_dir_path_ = "/data/local/tmp/idmap2-tests-XXXXXX";
#else
@@ -136,7 +136,7 @@ class Idmap2Tests : public testing::Test {
idmap_path_ = tmp_dir_path_ + "/a.idmap";
}
- virtual void TearDown() {
+ void TearDown() override {
EXPECT_EQ(rmdir(tmp_dir_path_.c_str()), 0)
<< "Failed to remove temporary directory " << tmp_dir_path_ << ": " << strerror(errno);
}
diff --git a/cmds/idmap2/tests/XmlParserTests.cpp b/cmds/idmap2/tests/XmlParserTests.cpp
new file mode 100644
index 000000000000..1a7eaca4d67b
--- /dev/null
+++ b/cmds/idmap2/tests/XmlParserTests.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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 <cstdio> // fclose
+#include <memory>
+#include <string>
+
+#include "TestHelpers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "idmap2/XmlParser.h"
+#include "idmap2/ZipFile.h"
+
+namespace android::idmap2 {
+
+Result<std::unique_ptr<const XmlParser>> CreateTestParser(const std::string& test_file) {
+ auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
+ if (zip == nullptr) {
+ return Error("Failed to open zip file");
+ }
+
+ auto data = zip->Uncompress(test_file);
+ if (data == nullptr) {
+ return Error("Failed to open xml file");
+ }
+
+ return XmlParser::Create(data->buf, data->size, /* copy_data */ true);
+}
+
+TEST(XmlParserTests, Create) {
+ auto xml = CreateTestParser("AndroidManifest.xml");
+ ASSERT_TRUE(xml) << xml.GetErrorMessage();
+
+ fclose(stderr); // silence expected warnings from libandroidfw
+ const char* not_xml = "foo";
+ auto fail = XmlParser::Create(reinterpret_cast<const uint8_t*>(not_xml), strlen(not_xml));
+ ASSERT_FALSE(fail);
+}
+
+TEST(XmlParserTests, NextChild) {
+ auto xml = CreateTestParser("res/xml/test.xml");
+ ASSERT_TRUE(xml) << xml.GetErrorMessage();
+
+ auto root_iter = (*xml)->tree_iterator();
+ ASSERT_EQ(root_iter->event(), XmlParser::Event::START_TAG);
+ ASSERT_EQ(root_iter->name(), "a");
+
+ auto a_iter = root_iter.begin();
+ ASSERT_EQ(a_iter->event(), XmlParser::Event::START_TAG);
+ ASSERT_EQ(a_iter->name(), "b");
+
+ auto c_iter = a_iter.begin();
+ ASSERT_EQ(c_iter->event(), XmlParser::Event::START_TAG);
+ ASSERT_EQ(c_iter->name(), "c");
+
+ ++c_iter;
+ ASSERT_EQ(c_iter->event(), XmlParser::Event::END_TAG);
+ ASSERT_EQ(c_iter, a_iter.end());
+
+ ++a_iter;
+ ASSERT_EQ(a_iter->event(), XmlParser::Event::START_TAG);
+ ASSERT_EQ(a_iter->name(), "d");
+
+ // Skip the <e> tag.
+ ++a_iter;
+ ASSERT_EQ(a_iter->event(), XmlParser::Event::END_TAG);
+ ASSERT_EQ(a_iter, root_iter.end());
+}
+
+TEST(XmlParserTests, AttributeValues) {
+ auto xml = CreateTestParser("res/xml/test.xml");
+ ASSERT_TRUE(xml) << xml.GetErrorMessage();
+
+ // Start at the <a> tag.
+ auto root_iter = (*xml)->tree_iterator();
+
+ // Start at the <b> tag.
+ auto a_iter = root_iter.begin();
+ auto attribute_str = a_iter->GetAttributeStringValue("type_string");
+ ASSERT_TRUE(attribute_str);
+ ASSERT_EQ(*attribute_str, "fortytwo");
+
+ auto attribute_value = a_iter->GetAttributeValue("type_int_dec");
+ ASSERT_TRUE(attribute_value);
+ ASSERT_EQ(attribute_value->data, 42);
+
+ attribute_value = a_iter->GetAttributeValue("type_int_hex");
+ ASSERT_TRUE(attribute_value);
+ ASSERT_EQ(attribute_value->data, 42);
+
+ attribute_value = a_iter->GetAttributeValue("type_int_boolean");
+ ASSERT_TRUE(attribute_value);
+ ASSERT_EQ(attribute_value->data, 0xffffffff);
+}
+
+TEST(XmlParserTests, IteratorEquality) {
+ auto xml = CreateTestParser("res/xml/test.xml");
+ ASSERT_TRUE(xml) << xml.GetErrorMessage();
+
+ // Start at the <a> tag.
+ auto root_iter_1 = (*xml)->tree_iterator();
+ auto root_iter_2 = (*xml)->tree_iterator();
+ ASSERT_EQ(root_iter_1, root_iter_2);
+ ASSERT_EQ(*root_iter_1, *root_iter_2);
+
+ // Start at the <b> tag.
+ auto a_iter_1 = root_iter_1.begin();
+ auto a_iter_2 = root_iter_2.begin();
+ ASSERT_NE(a_iter_1, root_iter_1.end());
+ ASSERT_NE(a_iter_2, root_iter_2.end());
+ ASSERT_EQ(a_iter_1, a_iter_2);
+ ASSERT_EQ(*a_iter_1, *a_iter_2);
+
+ // Move to the <d> tag.
+ ++a_iter_1;
+ ++a_iter_2;
+ ASSERT_NE(a_iter_1, root_iter_1.end());
+ ASSERT_NE(a_iter_2, root_iter_2.end());
+ ASSERT_EQ(a_iter_1, a_iter_2);
+ ASSERT_EQ(*a_iter_1, *a_iter_2);
+
+ // Move to the end of the <a> tag.
+ ++a_iter_1;
+ ++a_iter_2;
+ ASSERT_EQ(a_iter_1, root_iter_1.end());
+ ASSERT_EQ(a_iter_2, root_iter_2.end());
+ ASSERT_EQ(a_iter_1, a_iter_2);
+ ASSERT_EQ(*a_iter_1, *a_iter_2);
+}
+
+TEST(XmlParserTests, Backtracking) {
+ auto xml = CreateTestParser("res/xml/test.xml");
+ ASSERT_TRUE(xml) << xml.GetErrorMessage();
+
+ // Start at the <a> tag.
+ auto root_iter_1 = (*xml)->tree_iterator();
+
+ // Start at the <b> tag.
+ auto a_iter_1 = root_iter_1.begin();
+
+ // Start a second iterator at the <a> tag.
+ auto root_iter_2 = root_iter_1;
+ ASSERT_EQ(root_iter_1, root_iter_2);
+ ASSERT_EQ(*root_iter_1, *root_iter_2);
+
+ // Move the first iterator to the end of the <a> tag.
+ auto root_iter_end_1 = root_iter_1.end();
+ ++root_iter_1;
+ ASSERT_NE(root_iter_1, root_iter_2);
+ ASSERT_NE(*root_iter_1, *root_iter_2);
+
+ // Move to the <d> tag.
+ ++a_iter_1;
+ ASSERT_NE(a_iter_1, root_iter_end_1);
+
+ // Move to the end of the <a> tag.
+ ++a_iter_1;
+ ASSERT_EQ(a_iter_1, root_iter_end_1);
+}
+
+} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/XmlTests.cpp b/cmds/idmap2/tests/XmlTests.cpp
deleted file mode 100644
index df63211a9209..000000000000
--- a/cmds/idmap2/tests/XmlTests.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2018 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 <cstdio> // fclose
-
-#include "TestHelpers.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "idmap2/Xml.h"
-#include "idmap2/ZipFile.h"
-
-using ::testing::IsNull;
-using ::testing::NotNull;
-
-namespace android::idmap2 {
-
-TEST(XmlTests, Create) {
- auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
- ASSERT_THAT(zip, NotNull());
-
- auto data = zip->Uncompress("AndroidManifest.xml");
- ASSERT_THAT(data, NotNull());
-
- auto xml = Xml::Create(data->buf, data->size);
- ASSERT_THAT(xml, NotNull());
-
- fclose(stderr); // silence expected warnings from libandroidfw
- const char* not_xml = "foo";
- auto fail = Xml::Create(reinterpret_cast<const uint8_t*>(not_xml), strlen(not_xml));
- ASSERT_THAT(fail, IsNull());
-}
-
-TEST(XmlTests, FindTag) {
- auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
- ASSERT_THAT(zip, NotNull());
-
- auto data = zip->Uncompress("res/xml/test.xml");
- ASSERT_THAT(data, NotNull());
-
- auto xml = Xml::Create(data->buf, data->size);
- ASSERT_THAT(xml, NotNull());
-
- auto attrs = xml->FindTag("c");
- ASSERT_THAT(attrs, NotNull());
- ASSERT_EQ(attrs->size(), 4U);
- ASSERT_EQ(attrs->at("type_string"), "fortytwo");
- ASSERT_EQ(std::stoi(attrs->at("type_int_dec")), 42);
- ASSERT_EQ(std::stoi(attrs->at("type_int_hex")), 42);
- ASSERT_NE(std::stoul(attrs->at("type_int_boolean")), 0U);
-
- auto fail = xml->FindTag("does-not-exist");
- ASSERT_THAT(fail, IsNull());
-}
-
-} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/data/overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/overlay/AndroidManifest.xml
index 619bb6ce0f25..cf3691c3b3cf 100644
--- a/cmds/idmap2/tests/data/overlay/AndroidManifest.xml
+++ b/cmds/idmap2/tests/data/overlay/AndroidManifest.xml
@@ -16,8 +16,11 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="test.overlay">
+
<application android:hasCode="false"/>
+
<overlay
android:targetPackage="test.target"
- android:targetName="TestResources"/>
+ android:targetName="TestResources"
+ android:resourcesMap="@xml/overlays"/>
</manifest>
diff --git a/cmds/idmap2/tests/data/overlay/build b/cmds/idmap2/tests/data/overlay/build
index 68b9f507a11d..b921b0d3d3ad 100755
--- a/cmds/idmap2/tests/data/overlay/build
+++ b/cmds/idmap2/tests/data/overlay/build
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+FRAMEWORK_RES_APK=${ANDROID_PRODUCT_OUT}/system/framework/framework-res.apk
aapt2 compile --dir res -o compiled.flata
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
index 18ee43dc57a4..7c25985e5a61 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
index 642519008b15..c75f3e1dbddf 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
index 642ab90d00ae..5b8a6e4a90ed 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
index 2ec56020c4aa..698a1fd6e702 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay.apk b/cmds/idmap2/tests/data/overlay/overlay.apk
index 5842da4f432e..1db303ff05b5 100644
--- a/cmds/idmap2/tests/data/overlay/overlay.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/res/xml/overlays.xml b/cmds/idmap2/tests/data/overlay/res/xml/overlays.xml
new file mode 100644
index 000000000000..edd33f7dc90d
--- /dev/null
+++ b/cmds/idmap2/tests/data/overlay/res/xml/overlays.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<overlay>
+ <item target="string/str1" value="@string/str1"/>
+ <item target="string/str3" value="@string/str3" />
+ <item target="string/str4" value="@string/str4" />
+ <item target="integer/int1" value="@integer/int1" />
+ <item target="integer/not_in_target" value="@integer/not_in_target" />
+</overlay>
+
diff --git a/cmds/idmap2/tests/data/overlay/res/xml/overlays_different_package.xml b/cmds/idmap2/tests/data/overlay/res/xml/overlays_different_package.xml
new file mode 100644
index 000000000000..aa7fefaa305e
--- /dev/null
+++ b/cmds/idmap2/tests/data/overlay/res/xml/overlays_different_package.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<overlay>
+ <item target="string/str1" value="@android:string/ok"/>
+ <item target="string/str3" value="@string/str3" />
+</overlay>
+
diff --git a/cmds/idmap2/tests/data/overlay/res/xml/overlays_inline.xml b/cmds/idmap2/tests/data/overlay/res/xml/overlays_inline.xml
new file mode 100644
index 000000000000..e12b823ff50d
--- /dev/null
+++ b/cmds/idmap2/tests/data/overlay/res/xml/overlays_inline.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<overlay>
+ <item target="string/str1" value="Hello World"/>
+ <item target="integer/int1" value="73" />
+</overlay>
+
diff --git a/cmds/idmap2/tests/data/overlay/res/xml/overlays_swap.xml b/cmds/idmap2/tests/data/overlay/res/xml/overlays_swap.xml
new file mode 100644
index 000000000000..5728e672d94a
--- /dev/null
+++ b/cmds/idmap2/tests/data/overlay/res/xml/overlays_swap.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<overlay>
+ <item target="string/str1" value="@string/str4"/>
+ <item target="string/str3" value="@string/str1" />
+ <item target="string/str4" value="@string/str3" />
+ <item target="integer/int_not_in_target" value="@integer/int1" />
+</overlay>
diff --git a/cmds/idmap2/tests/data/target/res/xml/test.xml b/cmds/idmap2/tests/data/target/res/xml/test.xml
index 0fe21c6b6d0a..56a3f7f0b13a 100644
--- a/cmds/idmap2/tests/data/target/res/xml/test.xml
+++ b/cmds/idmap2/tests/data/target/res/xml/test.xml
@@ -14,12 +14,15 @@
limitations under the License.
-->
<a>
- <b>
- <c
- type_string="fortytwo"
- type_int_dec="42"
- type_int_hex="0x2a"
- type_int_boolean="true"
- />
+ <b type_string="fortytwo"
+ type_int_dec="42"
+ type_int_hex="0x2a"
+ type_int_boolean="true">
+
+ <c />
</b>
-</a>
+
+ <d>
+ <e />
+ </d>
+</a> \ No newline at end of file
diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
index 033305aaed4f..2eb7c477c3b4 100644
--- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk
+++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index 9bcd6dcabcde..251cf46f969d 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/cmds/idmap2/valgrind.sh b/cmds/idmap2/valgrind.sh
new file mode 100755
index 000000000000..b4ebab0c7ffe
--- /dev/null
+++ b/cmds/idmap2/valgrind.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+#
+# 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.
+#
+
+function _log()
+{
+ echo -e "$*" >&2
+}
+
+function _eval()
+{
+ local label="$1"
+ local cmd="$2"
+ local red="\e[31m"
+ local green="\e[32m"
+ local reset="\e[0m"
+ local output
+
+ _log "${green}[ RUN ]${reset} ${label}"
+ output="$(eval "$cmd" 2>&1)"
+ if [[ $? -eq 0 ]]; then
+ _log "${green}[ OK ]${reset} ${label}"
+ return 0
+ else
+ echo "${output}"
+ _log "${red}[ FAILED ]${reset} ${label}"
+ errors=$((errors + 1))
+ return 1
+ fi
+}
+
+errors=0
+script="$(readlink -f "$BASH_SOURCE")"
+prefix="$(dirname "$script")"
+target_path="${prefix}/tests/data/target/target.apk"
+overlay_path="${prefix}/tests/data/overlay/overlay.apk"
+idmap_path="/tmp/a.idmap"
+valgrind="valgrind --error-exitcode=1 -q --track-origins=yes --leak-check=full"
+
+_eval "idmap2 create" "$valgrind idmap2 create --policy public --target-apk-path $target_path --overlay-apk-path $overlay_path --idmap-path $idmap_path"
+_eval "idmap2 dump" "$valgrind idmap2 dump --idmap-path $idmap_path"
+_eval "idmap2 lookup" "$valgrind idmap2 lookup --idmap-path $idmap_path --config '' --resid test.target:string/str1"
+_eval "idmap2 scan" "$valgrind idmap2 scan --input-directory ${prefix}/tests/data/overlay --recursive --target-package-name test.target --target-apk-path $target_path --output-directory /tmp --override-policy public"
+_eval "idmap2 verify" "$valgrind idmap2 verify --idmap-path $idmap_path"
+_eval "idmap2_tests" "$valgrind $ANDROID_HOST_OUT/nativetest64/idmap2_tests/idmap2_tests"
+exit $errors
diff --git a/cmds/locksettings/TEST_MAPPING b/cmds/locksettings/TEST_MAPPING
new file mode 100644
index 000000000000..56f5cc034f05
--- /dev/null
+++ b/cmds/locksettings/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit-devicepolicy": [
+ {
+ "name": "CtsDevicePolicyManagerTestCases",
+ "options": [
+ {
+ "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 8944dedd6c96..cb2732561b56 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -51,11 +51,6 @@ cc_defaults {
srcs: [
":statsd_aidl",
"src/active_config_list.proto",
- "src/statsd_config.proto",
- "src/uid_data.proto",
- "src/FieldValue.cpp",
- "src/hash.cpp",
- "src/stats_log_util.cpp",
"src/anomaly/AlarmMonitor.cpp",
"src/anomaly/AlarmTracker.cpp",
"src/anomaly/AnomalyTracker.cpp",
@@ -63,51 +58,59 @@ cc_defaults {
"src/anomaly/subscriber_util.cpp",
"src/condition/CombinationConditionTracker.cpp",
"src/condition/condition_util.cpp",
- "src/condition/SimpleConditionTracker.cpp",
"src/condition/ConditionWizard.cpp",
- "src/condition/StateTracker.cpp",
+ "src/condition/SimpleConditionTracker.cpp",
+ "src/condition/StateConditionTracker.cpp",
"src/config/ConfigKey.cpp",
"src/config/ConfigListener.cpp",
"src/config/ConfigManager.cpp",
"src/external/GpuStatsPuller.cpp",
"src/external/Perfetto.cpp",
- "src/external/StatsPuller.cpp",
+ "src/external/PowerStatsPuller.cpp",
+ "src/external/puller_util.cpp",
+ "src/external/ResourceHealthManagerPuller.cpp",
"src/external/StatsCallbackPuller.cpp",
"src/external/StatsCompanionServicePuller.cpp",
+ "src/external/StatsPuller.cpp",
+ "src/external/StatsPullerManager.cpp",
"src/external/SubsystemSleepStatePuller.cpp",
- "src/external/PowerStatsPuller.cpp",
- "src/external/ResourceHealthManagerPuller.cpp",
+ "src/external/SurfaceflingerStatsPuller.cpp",
"src/external/TrainInfoPuller.cpp",
- "src/external/StatsPullerManager.cpp",
- "src/external/puller_util.cpp",
+ "src/FieldValue.cpp",
+ "src/guardrail/StatsdStats.cpp",
+ "src/hash.cpp",
+ "src/HashableDimensionKey.cpp",
"src/logd/LogEvent.cpp",
"src/logd/LogEventQueue.cpp",
"src/matchers/CombinationLogMatchingTracker.cpp",
"src/matchers/EventMatcherWizard.cpp",
"src/matchers/matcher_util.cpp",
"src/matchers/SimpleLogMatchingTracker.cpp",
- "src/metrics/MetricProducer.cpp",
- "src/metrics/EventMetricProducer.cpp",
"src/metrics/CountMetricProducer.cpp",
- "src/metrics/DurationMetricProducer.cpp",
- "src/metrics/duration_helper/OringDurationTracker.cpp",
"src/metrics/duration_helper/MaxDurationTracker.cpp",
- "src/metrics/ValueMetricProducer.cpp",
+ "src/metrics/duration_helper/OringDurationTracker.cpp",
+ "src/metrics/DurationMetricProducer.cpp",
+ "src/metrics/EventMetricProducer.cpp",
"src/metrics/GaugeMetricProducer.cpp",
- "src/metrics/MetricsManager.cpp",
+ "src/metrics/MetricProducer.cpp",
"src/metrics/metrics_manager_util.cpp",
+ "src/metrics/MetricsManager.cpp",
+ "src/metrics/ValueMetricProducer.cpp",
"src/packages/UidMap.cpp",
- "src/storage/StorageManager.cpp",
+ "src/shell/shell_config.proto",
+ "src/shell/ShellSubscriber.cpp",
+ "src/socket/StatsSocketListener.cpp",
+ "src/state/StateManager.cpp",
+ "src/state/StateTracker.cpp",
+ "src/stats_log_util.cpp",
+ "src/statscompanion_util.cpp",
+ "src/statsd_config.proto",
"src/StatsLogProcessor.cpp",
"src/StatsService.cpp",
- "src/statscompanion_util.cpp",
+ "src/storage/StorageManager.cpp",
"src/subscriber/IncidentdReporter.cpp",
"src/subscriber/SubscriberReporter.cpp",
- "src/HashableDimensionKey.cpp",
- "src/guardrail/StatsdStats.cpp",
- "src/socket/StatsSocketListener.cpp",
- "src/shell/ShellSubscriber.cpp",
- "src/shell/shell_config.proto",
+ "src/uid_data.proto",
],
local_include_dirs: [
@@ -120,26 +123,25 @@ cc_defaults {
],
shared_libs: [
+ "android.frameworks.stats@1.0",
+ "android.hardware.health@2.0",
+ "android.hardware.power.stats@1.0",
+ "android.hardware.power@1.0",
+ "android.hardware.power@1.1",
"libbase",
"libbinder",
+ "libcutils",
"libgraphicsenv",
+ "libhidlbase",
"libincident",
"liblog",
- "libutils",
- "libservices",
"libprotoutil",
+ "libservices",
"libstatslog",
- "libhardware",
- "libhardware_legacy",
- "libhidlbase",
- "android.frameworks.stats@1.0",
- "android.hardware.health@2.0",
- "android.hardware.power@1.0",
- "android.hardware.power@1.1",
- "android.hardware.power.stats@1.0",
- "libpackagelistparser",
+ "libstatssocket",
"libsysutils",
- "libcutils",
+ "libtimestats_proto",
+ "libutils",
],
}
@@ -213,57 +215,56 @@ cc_test {
"src/atom_field_options.proto",
"src/atoms.proto",
- "src/stats_log.proto",
"src/shell/shell_data.proto",
+ "src/stats_log.proto",
"tests/AlarmMonitor_test.cpp",
"tests/anomaly/AlarmTracker_test.cpp",
"tests/anomaly/AnomalyTracker_test.cpp",
+ "tests/condition/CombinationConditionTracker_test.cpp",
+ "tests/condition/ConditionTimer_test.cpp",
+ "tests/condition/SimpleConditionTracker_test.cpp",
+ "tests/condition/StateConditionTracker_test.cpp",
"tests/ConfigManager_test.cpp",
- "tests/external/puller_util_test.cpp",
+ "tests/e2e/Alarm_e2e_test.cpp",
+ "tests/e2e/Anomaly_count_e2e_test.cpp",
+ "tests/e2e/Anomaly_duration_sum_e2e_test.cpp",
+ "tests/e2e/Attribution_e2e_test.cpp",
+ "tests/e2e/ConfigTtl_e2e_test.cpp",
+ "tests/e2e/DurationMetric_e2e_test.cpp",
+ "tests/e2e/GaugeMetric_e2e_pull_test.cpp",
+ "tests/e2e/GaugeMetric_e2e_push_test.cpp",
+ "tests/e2e/MetricActivation_e2e_test.cpp",
+ "tests/e2e/MetricConditionLink_e2e_test.cpp",
+ "tests/e2e/PartialBucket_e2e_test.cpp",
+ "tests/e2e/ValueMetric_pull_e2e_test.cpp",
+ "tests/e2e/WakelockDuration_e2e_test.cpp",
"tests/external/GpuStatsPuller_test.cpp",
"tests/external/IncidentReportArgs_test.cpp",
+ "tests/external/puller_util_test.cpp",
"tests/external/StatsPuller_test.cpp",
+ "tests/external/SurfaceflingerStatsPuller_test.cpp",
+ "tests/FieldValue_test.cpp",
+ "tests/guardrail/StatsdStats_test.cpp",
"tests/indexed_priority_queue_test.cpp",
+ "tests/log_event/LogEventQueue_test.cpp",
"tests/LogEntryMatcher_test.cpp",
"tests/LogEvent_test.cpp",
- "tests/log_event/LogEventQueue_test.cpp",
- "tests/MetricsManager_test.cpp",
- "tests/StatsLogProcessor_test.cpp",
- "tests/StatsService_test.cpp",
- "tests/UidMap_test.cpp",
- "tests/FieldValue_test.cpp",
- "tests/condition/CombinationConditionTracker_test.cpp",
- "tests/condition/SimpleConditionTracker_test.cpp",
- "tests/condition/StateTracker_test.cpp",
- "tests/condition/ConditionTimer_test.cpp",
- "tests/metrics/OringDurationTracker_test.cpp",
- "tests/metrics/MaxDurationTracker_test.cpp",
"tests/metrics/CountMetricProducer_test.cpp",
"tests/metrics/DurationMetricProducer_test.cpp",
"tests/metrics/EventMetricProducer_test.cpp",
- "tests/metrics/ValueMetricProducer_test.cpp",
"tests/metrics/GaugeMetricProducer_test.cpp",
- "tests/guardrail/StatsdStats_test.cpp",
+ "tests/metrics/MaxDurationTracker_test.cpp",
"tests/metrics/metrics_test_helper.cpp",
+ "tests/metrics/OringDurationTracker_test.cpp",
+ "tests/metrics/ValueMetricProducer_test.cpp",
+ "tests/MetricsManager_test.cpp",
+ "tests/shell/ShellSubscriber_test.cpp",
+ "tests/state/StateTracker_test.cpp",
"tests/statsd_test_util.cpp",
+ "tests/StatsLogProcessor_test.cpp",
+ "tests/StatsService_test.cpp",
"tests/storage/StorageManager_test.cpp",
- "tests/e2e/WakelockDuration_e2e_test.cpp",
- "tests/e2e/MetricActivation_e2e_test.cpp",
- "tests/e2e/MetricConditionLink_e2e_test.cpp",
- "tests/e2e/Alarm_e2e_test.cpp",
- "tests/e2e/Attribution_e2e_test.cpp",
- "tests/e2e/GaugeMetric_e2e_push_test.cpp",
- "tests/e2e/GaugeMetric_e2e_pull_test.cpp",
- "tests/e2e/ValueMetric_pull_e2e_test.cpp",
- "tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp",
- "tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp",
- "tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp",
- "tests/e2e/Anomaly_count_e2e_test.cpp",
- "tests/e2e/Anomaly_duration_sum_e2e_test.cpp",
- "tests/e2e/ConfigTtl_e2e_test.cpp",
- "tests/e2e/PartialBucket_e2e_test.cpp",
- "tests/e2e/DurationMetric_e2e_test.cpp",
- "tests/shell/ShellSubscriber_test.cpp",
+ "tests/UidMap_test.cpp",
],
static_libs: [
@@ -293,17 +294,17 @@ cc_benchmark {
// not included in libprotobuf-cpp-lite, so compile it here.
":libprotobuf-internal-protos",
- "src/atom_field_options.proto",
- "src/atoms.proto",
- "src/stats_log.proto",
- "benchmark/main.cpp",
- "benchmark/hello_world_benchmark.cpp",
- "benchmark/log_event_benchmark.cpp",
- "benchmark/stats_write_benchmark.cpp",
+ "benchmark/duration_metric_benchmark.cpp",
"benchmark/filter_value_benchmark.cpp",
"benchmark/get_dimensions_for_condition_benchmark.cpp",
+ "benchmark/hello_world_benchmark.cpp",
+ "benchmark/log_event_benchmark.cpp",
+ "benchmark/main.cpp",
"benchmark/metric_util.cpp",
- "benchmark/duration_metric_benchmark.cpp",
+ "benchmark/stats_write_benchmark.cpp",
+ "src/atom_field_options.proto",
+ "src/atoms.proto",
+ "src/stats_log.proto",
],
proto: {
@@ -343,11 +344,11 @@ java_library {
},
srcs: [
- "src/stats_log.proto",
- "src/statsd_config.proto",
"src/atoms.proto",
"src/shell/shell_config.proto",
"src/shell/shell_data.proto",
+ "src/stats_log.proto",
+ "src/statsd_config.proto",
],
static_libs: [
diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS
index 380e499a5abf..04464ce02b4f 100644
--- a/cmds/statsd/OWNERS
+++ b/cmds/statsd/OWNERS
@@ -3,5 +3,6 @@ joeo@google.com
jtnguyen@google.com
muhammadq@google.com
singhtejinder@google.com
+tsaichristine@google.com
yaochen@google.com
yro@google.com
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index 13f5c8ae5fd8..84a06070e431 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -116,28 +116,13 @@ void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* ou
}
bool isAttributionUidField(const FieldValue& value) {
- int field = value.mField.getField() & 0xff007f;
- if (field == 0x10001 && value.mValue.getType() == INT) {
- return true;
- }
- return false;
+ return isAttributionUidField(value.mField, value.mValue);
}
int32_t getUidIfExists(const FieldValue& value) {
- bool isUid = false;
// the field is uid field if the field is the uid field in attribution node or marked as
// is_uid in atoms.proto
- if (isAttributionUidField(value)) {
- isUid = true;
- } else {
- auto it = android::util::AtomsInfo::kAtomsWithUidField.find(value.mField.getTag());
- if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) {
- int uidField = it->second; // uidField is the field number in proto
- isUid = value.mField.getDepth() == 0 && value.mField.getPosAtDepth(0) == uidField &&
- value.mValue.getType() == INT;
- }
- }
-
+ bool isUid = isAttributionUidField(value) || isUidField(value.mField, value.mValue);
return isUid ? value.mValue.int_value : -1;
}
@@ -149,6 +134,18 @@ bool isAttributionUidField(const Field& field, const Value& value) {
return false;
}
+bool isUidField(const Field& field, const Value& value) {
+ auto it = android::util::AtomsInfo::kAtomsWithUidField.find(field.getTag());
+
+ if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) {
+ int uidField = it->second; // uidField is the field number in proto
+ return field.getDepth() == 0 && field.getPosAtDepth(0) == uidField &&
+ value.getType() == INT;
+ }
+
+ return false;
+}
+
Value::Value(const Value& from) {
type = from.getType();
switch (type) {
@@ -464,4 +461,4 @@ bool HasPositionALL(const FieldMatcher& matcher) {
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 6729e052b5ee..0e033e06c203 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -392,6 +392,7 @@ int getUidIfExists(const FieldValue& value);
void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output);
bool isAttributionUidField(const Field& field, const Value& value);
+bool isUidField(const Field& field, const Value& value);
bool equalDimensions(const std::vector<Matcher>& dimension_a,
const std::vector<Matcher>& dimension_b);
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index af8b3af6ea61..5e156bb26caa 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -59,6 +59,16 @@ android::hash_t hashDimension(const HashableDimensionKey& value) {
return JenkinsHashWhiten(hash);
}
+bool filterValues(const Matcher& matcherField, const vector<FieldValue>& values, Value* output) {
+ for (const auto& value : values) {
+ if (value.mField.matches(matcherField)) {
+ (*output) = value.mValue;
+ return true;
+ }
+ }
+ return false;
+}
+
bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
HashableDimensionKey* output) {
size_t num_matches = 0;
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index 6f4941f717ee..a12385057585 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -120,6 +120,13 @@ class MetricDimensionKey {
android::hash_t hashDimension(const HashableDimensionKey& key);
/**
+ * Returns true if a FieldValue field matches the matcher field.
+ * The value of the FieldValue is output.
+ */
+bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& values,
+ Value* output);
+
+/**
* Creating HashableDimensionKeys from FieldValues using matcher.
*
* This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
@@ -169,4 +176,4 @@ struct hash<MetricDimensionKey> {
return android::JenkinsHashWhiten(hash);
}
};
-} // namespace std \ No newline at end of file
+} // namespace std
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index f0db1b0128a1..3d002d2efdd0 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -248,19 +248,6 @@ private:
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition);
-
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition);
-
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
-
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 1c7180ffbde1..b665a8b99fbd 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -266,7 +266,9 @@ status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* rep
IResultReceiver::asInterface(data.readStrongBinder());
err = command(in, out, err, args, resultReceiver);
- resultReceiver->send(err);
+ if (resultReceiver != nullptr) {
+ resultReceiver->send(err);
+ }
return NO_ERROR;
}
default: { return BnStatsManager::onTransact(code, data, reply, flags); }
@@ -411,13 +413,20 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
return cmd_trigger_active_config_broadcast(out, args);
}
if (!args[0].compare(String8("data-subscribe"))) {
- if (mShellSubscriber == nullptr) {
- mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
+ {
+ std::lock_guard<std::mutex> lock(mShellSubscriberMutex);
+ if (mShellSubscriber == nullptr) {
+ mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
+ }
}
int timeoutSec = -1;
if (argCount >= 2) {
timeoutSec = atoi(args[1].c_str());
}
+ if (resultReceiver == nullptr) {
+ ALOGI("Null resultReceiver given, no subscription will be started");
+ return UNEXPECTED_NULL;
+ }
mShellSubscriber->startNewSubscription(in, out, resultReceiver, timeoutSec);
return NO_ERROR;
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 53b6ce989195..949094871936 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -432,6 +432,10 @@ private:
sp<ShellSubscriber> mShellSubscriber;
+ /**
+ * Mutex for setting the shell subscriber
+ */
+ mutable mutex mShellSubscriberMutex;
std::shared_ptr<LogEventQueue> mEventQueue;
FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 32d90b70c34e..6249de3d3bac 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -56,6 +56,8 @@ import "frameworks/base/core/proto/android/telecomm/enums.proto";
import "frameworks/base/core/proto/android/telephony/enums.proto";
import "frameworks/base/core/proto/android/view/enums.proto";
import "frameworks/base/core/proto/android/wifi/enums.proto";
+import "frameworks/base/core/proto/android/stats/textclassifier/textclassifier_enums.proto";
+import "frameworks/base/core/proto/android/stats/otaupdate/updateengine_enums.proto";
/**
* The master atom class. This message defines all of the available
@@ -295,6 +297,7 @@ message Atom {
MediametricsMediadrmReported mediametrics_mediadrm_reported = 198;
MediametricsNuPlayerReported mediametrics_nuplayer_reported = 199;
MediametricsRecorderReported mediametrics_recorder_reported = 200;
+ MediametricsDrmManagerReported mediametrics_drmmanager_reported = 201;
CarPowerStateChanged car_power_state_changed = 203;
GarageModeInfo garage_mode_info = 204;
TestAtomReported test_atom_reported = 205 [(log_from_module) = "cts"];
@@ -319,15 +322,25 @@ message Atom {
217 [(log_from_module) = "permissioncontroller"];
PermissionAppsFragmentViewed permission_apps_fragment_viewed =
218 [(log_from_module) = "permissioncontroller"];
+ TextSelectionEvent text_selection_event =
+ 219 [(log_from_module) = "textclassifier"];
+ TextLinkifyEvent text_linkify_event =
+ 220 [(log_from_module) = "textclassifier"];
+ ConversationActionsEvent conversation_actions_event =
+ 221 [(log_from_module) = "textclassifier"];
+ LanguageDetectionEvent language_detection_event =
+ 222 [(log_from_module) = "textclassifier"];
ExclusionRectStateChanged exclusion_rect_state_changed = 223;
BackGesture back_gesture_reported_reported = 224;
-
+ UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225;
+ UpdateEngineSuccessfulUpdateReported update_engine_successful_update_reported = 226;
+ CameraActionEvent camera_action_event = 227;
AppCompatibilityChangeReported app_compatibility_change_reported =
228 [(allow_from_any_uid) = true];
}
// Pulled events will start at field 10000.
- // Next: 10062
+ // Next: 10065
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000;
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -365,7 +378,6 @@ message Atom {
PowerProfile power_profile = 10033;
ProcStatsPkgProc proc_stats_pkg_proc = 10034;
ProcessCpuTime process_cpu_time = 10035;
- NativeProcessMemoryState native_process_memory_state = 10036;
CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
OnDevicePowerMeasurement on_device_power_measurement = 10038;
DeviceCalculatedPowerUse device_calculated_power_use = 10039;
@@ -391,11 +403,16 @@ message Atom {
CoolingDevice cooling_device = 10059;
AppOps app_ops = 10060;
ProcessSystemIonHeapSize process_system_ion_heap_size = 10061;
+ SurfaceflingerStatsGlobalInfo surfaceflinger_stats_global_info = 10062;
+ SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063;
+ ProcessMemorySnapshot process_memory_snapshot = 10064;
}
// DO NOT USE field numbers above 100,000 in AOSP.
// Field numbers 100,000 - 199,999 are reserved for non-AOSP (e.g. OEMs) to use.
// Field numbers 200,000 and above are reserved for future use; do not use them at all.
+
+ reserved 10036;
}
/**
@@ -2605,12 +2622,14 @@ message SettingsUIChanged {
message TouchEventReported {
/**
* The fields latency_{min|max|mean|stdev} represent minimum, maximum, mean,
- * and the standard deviation of latency between the kernel and framework
- * for touchscreen events. The units are microseconds.
+ * and the standard deviation of the time spent processing touchscreen events
+ * in the kernel and inputflinger. The units are microseconds.
*
- * The number is measured as the difference between the time at which
- * the input event was received in the evdev driver,
- * and the time at which the input event was received in EventHub.
+ * On supported devices, the starting point is taken during the hard interrupt inside the
+ * kernel touch driver. On all other devices, the starting point is taken inside
+ * the kernel's input event subsystem upon receipt of the input event.
+ * The ending point is taken inside InputDispatcher, just after the input event
+ * is sent to the app.
*/
// Minimum value
optional float latency_min_micros = 1;
@@ -3052,9 +3071,9 @@ message PictureInPictureStateChanged {
* services/core/java/com/android/server/wm/Session.java
*/
message OverlayStateChanged {
- optional int32 uid = 1 [(is_uid) = true];
+ optional int32 uid = 1 [(state_field_option).option = PRIMARY, (is_uid) = true];
- optional string package_name = 2;
+ optional string package_name = 2 [(state_field_option).option = PRIMARY];
optional bool using_alert_window = 3;
@@ -3062,7 +3081,7 @@ message OverlayStateChanged {
ENTERED = 1;
EXITED = 2;
}
- optional State state = 4;
+ optional State state = 4 [(state_field_option).option = EXCLUSIVE];
}
/*
@@ -3955,7 +3974,7 @@ message ModemActivityInfo {
// rx time in ms at power level 5
optional uint64 controller_rx_time_millis = 9;
// product of current(mA), voltage(V) and time(ms)
- optional uint64 energy_used = 10;
+ optional uint64 energy_used = 10 [deprecated=true];
}
/**
@@ -4001,8 +4020,8 @@ message ProcessMemoryState {
optional int64 page_major_fault = 5;
// RSS
- // Value is read from /proc/PID/status. Or from memory.stat, field
- // total_rss if per-app memory cgroups are enabled.
+ // Value is read from memory.stat, field total_rss if per-app memory
+ // cgroups are enabled. Otherwise, value from /proc/pid/stat.
optional int64 rss_in_bytes = 6;
// CACHE
@@ -4012,67 +4031,52 @@ message ProcessMemoryState {
// SWAP
// Value is read from memory.stat, field total_swap if per-app memory
- // cgroups are enabled. Otherwise, VmSwap from /proc/PID/status.
+ // cgroups are enabled. Otherwise, 0.
optional int64 swap_in_bytes = 8;
- // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
+ // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always -1.
optional int64 rss_high_watermark_in_bytes = 9 [deprecated = true];
- // Elapsed real time when the process started.
- // Value is read from /proc/PID/stat, field 22. 0 if read from per-app memory cgroups.
- optional int64 start_time_nanos = 10;
+ // Deprecated: use ProcessMemorySnapshot atom instead. Always -1.
+ optional int64 start_time_nanos = 10 [deprecated = true];
- // Anonymous page size plus swap size. Values are read from /proc/PID/status.
- optional int32 anon_rss_and_swap_in_kilobytes = 11;
+ // Deprecated: use ProcessMemorySnapshot atom instead. Always -1.
+ optional int32 anon_rss_and_swap_in_kilobytes = 11 [deprecated = true];
}
/*
- * Logs the memory stats for a native process (from procfs).
+ * Logs the memory high-water mark for a process.
+ *
+ * Pulled from StatsCompanionService for all managed processes (from ActivityManagerServie)
+ * and for selected native processes.
*
- * Pulled from StatsCompanionService for selected native processes.
+ * Pulling this atom resets high-water mark counters for all processes.
*/
-message NativeProcessMemoryState {
+message ProcessMemoryHighWaterMark {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
// The process name.
- // Value read from /proc/PID/cmdline.
+ // Usually package name or process cmdline.
+ // Provided by ActivityManagerService or read from /proc/PID/cmdline.
optional string process_name = 2;
- // # of page-faults
- optional int64 page_fault = 3;
-
- // # of major page-faults
- optional int64 page_major_fault = 4;
-
- // RSS
- // Value read from /proc/PID/status.
- optional int64 rss_in_bytes = 5;
-
- // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
- optional int64 rss_high_watermark_in_bytes = 6 [deprecated = true];
+ // Deprecated: use rss_high_water_mark_in_kilobytes instead. This field is
+ // computed by converting kilobytes to bytes.
+ optional int64 rss_high_water_mark_in_bytes = 3 [deprecated = true];
- // Elapsed real time when the process started.
- // Value is read from /proc/PID/stat, field 22.
- optional int64 start_time_nanos = 7;
-
- // SWAP
- // Value read from /proc/PID/status, field VmSwap.
- optional int64 swap_in_bytes = 8;
-
- // Anonymous page size plus swap size. Values are read from /proc/PID/status.
- optional int32 anon_rss_and_swap_in_kilobytes = 9;
+ // RSS high-water mark. Peak RSS usage of the process. Read from the VmHWM field in
+ // /proc/PID/status.
+ optional int32 rss_high_water_mark_in_kilobytes = 4;
}
/*
- * Logs the memory high-water mark for a process.
+ * Logs the memory stats for a process.
*
- * Pulled from StatsCompanionService for all managed processes (from ActivityManagerServie)
+ * Pulled from StatsCompanionService for all managed processes (from ActivityManagerService)
* and for selected native processes.
- *
- * Pulling this atom resets high-water mark counters for all processes.
*/
-message ProcessMemoryHighWaterMark {
+message ProcessMemorySnapshot {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
@@ -4081,9 +4085,29 @@ message ProcessMemoryHighWaterMark {
// Provided by ActivityManagerService or read from /proc/PID/cmdline.
optional string process_name = 2;
- // RSS high-water mark. Peak RSS usage of the process. Read from the VmHWM field in
- // /proc/PID/status.
- optional int64 rss_high_water_mark_in_bytes = 3;
+ // The pid of the process.
+ // Allows to disambiguate instances of the process.
+ optional int32 pid = 3;
+
+ // The current OOM score adjustment value.
+ // Read from ProcessRecord for managed processes.
+ // Placeholder -1001 (OOM_SCORE_ADJ_MIN - 1, outside of allowed range) for native ones.
+ optional int32 oom_score_adj = 4;
+
+ // The current RSS of the process.
+ // VmRSS from /proc/pid/status.
+ optional int32 rss_in_kilobytes = 5;
+
+ // The current anon RSS of the process.
+ // RssAnon from /proc/pid/status.
+ optional int32 anon_rss_in_kilobytes = 6;
+
+ // The current swap size of the process.
+ // VmSwap from /proc/pid/status.
+ optional int32 swap_in_kilobytes = 7;
+
+ // The sum of rss_in_kilobytes and swap_in_kilobytes.
+ optional int32 anon_rss_and_swap_in_kilobytes = 8;
}
/*
@@ -6196,6 +6220,41 @@ message MediametricsNuPlayerReported {
}
/**
+ * Track Legacy DRM usage
+ * Logged from
+ * frameworks/av/drm/drmserver/DrmManager.cpp
+ */
+message MediametricsDrmManagerReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ enum Method {
+ METHOD_NOT_FOUND = -1;
+ GET_CONSTRAINTS = 0;
+ GET_METADATA = 1;
+ CAN_HANDLE = 2;
+ PROCESS_DRM_INFO = 3;
+ ACQUIRE_DRM_INFO = 4;
+ SAVE_RIGHTS = 5;
+ GET_ORIGINAL_MIME_TYPE = 6;
+ GET_DRM_OBJECT_TYPE = 7;
+ CHECK_RIGHTS_STATUS = 8;
+ REMOVE_RIGHTS = 9;
+ REMOVE_ALL_RIGHTS = 10;
+ OPEN_CONVERT_SESSION = 11;
+ OPEN_DECRYPT_SESSION = 12;
+ }
+
+ // plugin_id+description inform which Legacy DRM plugins are still in use on device
+ optional string plugin_id = 5;
+ optional string description = 6;
+ optional Method method = 7;
+ optional string mime_types = 8;
+}
+
+/**
* State of a dangerous permission requested by a package
*/
message DangerousPermissionState {
@@ -6404,6 +6463,9 @@ message GpuStatsAppInfo {
// CPU Vulkan implementation is in use.
optional bool cpu_vulkan_in_use = 6;
+
+ // App is not doing pre-rotation correctly.
+ optional bool false_prerotation = 7;
}
/*
@@ -6507,8 +6569,14 @@ message CoolingDevice {
* Logged from the Intelligence mainline module.
*/
message IntelligenceEventReported {
+ // The event type.
optional android.stats.intelligence.EventType event_id = 1;
+ // Success, failure.
optional android.stats.intelligence.Status status = 2;
+ // How many times the event occured (to report a batch of high frequency events).
+ optional int32 count = 3;
+ // How long the event took (sum of durations if count > 1)
+ optional int64 duration_millis = 4;
}
/**
@@ -6824,6 +6892,317 @@ message PermissionAppsFragmentViewed {
}
/**
+ * Logs when there is a smart selection related event.
+ * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
+ * Logged from: TextClassifierEventLogger.java
+ */
+message TextSelectionEvent {
+ // A session ID.
+ optional string session_id = 1;
+
+ // Event type of this event.
+ optional android.stats.textclassifier.EventType event_type = 2;
+
+ // Name of the model that is involved in this event.
+ optional string model_name = 3;
+
+ // Type of widget that was involved in triggering this event.
+ optional android.stats.textclassifier.WidgetType widget_type = 4;
+
+ // Index of this event in a session.
+ optional int32 event_index = 5;
+
+ // Entity type that is involved.
+ optional string entity_type = 6;
+
+ // Relative word index of the start of the selection.
+ optional int32 relative_word_start_index = 7;
+
+ // Relative word (exclusive) index of the end of the selection.
+ optional int32 relative_word_end_index = 8;
+
+ // Relative word index of the start of the smart selection.
+ optional int32 relative_suggested_word_start_index = 9;
+
+ // Relative word (exclusive) index of the end of the smart selection.
+ optional int32 relative_suggested_word_end_index = 10;
+
+ // Name of source package.
+ optional string package_name = 11;
+}
+
+/**
+ * Logs when there is a smart linkify related event.
+ * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
+ * Logged from: TextClassifierEventLogger.java
+ */
+message TextLinkifyEvent {
+ // A session ID.
+ optional string session_id = 1;
+
+ // Event type of this event.
+ optional android.stats.textclassifier.EventType event_type = 2;
+
+ // Name of the model that is involved in this event.
+ optional string model_name = 3;
+
+ // Type of widget that was involved in triggering this event.
+ optional android.stats.textclassifier.WidgetType widget_type = 4;
+
+ // Index of this event in a session.
+ optional int32 event_index = 5;
+
+ // Entity type that is involved.
+ optional string entity_type = 6;
+
+ // Number of links detected.
+ optional int32 num_links = 7;
+
+ // The total length of all links.
+ optional int32 linked_text_length = 8;
+
+ // Length of input text.
+ optional int32 text_length = 9;
+
+ // Time spent on generating links in ms.
+ optional int64 latency_millis = 10;
+
+ // Name of source package.
+ optional string package_name = 11;
+}
+
+/**
+ * Logs when there is a conversation actions related event.
+ * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
+ * Logged from: TextClassifierEventLogger.java
+ */
+message ConversationActionsEvent {
+ // A session ID.
+ optional string session_id = 1;
+
+ // Event type of this event.
+ optional android.stats.textclassifier.EventType event_type = 2;
+
+ // Name of the model that is involved in this event.
+ optional string model_name = 3;
+
+ // Type of widget that was involved in triggering this event.
+ optional android.stats.textclassifier.WidgetType widget_type = 4;
+
+ // The first entity type that is involved.
+ optional string first_entity_type = 5;
+
+ // The second entity type that is involved.
+ optional string second_entity_type = 6;
+
+ // The third entity type that is involved.
+ optional string third_entity_type = 7;
+
+ // The score of the first entity type.
+ optional float score = 8;
+
+ // Name of source package.
+ optional string package_name = 9;
+}
+
+/**
+ * Logs when there is a language detection related event.
+ * See frameworks/base/core/java/android/view/textclassifier/TextClassifierEvent.java
+ * Logged from: TextClassifierEventLogger.java
+ */
+message LanguageDetectionEvent {
+ // A session ID.
+ optional string session_id = 1;
+
+ // Event type of this event.
+ optional android.stats.textclassifier.EventType event_type = 2;
+
+ // Name of the model that is involved in this event.
+ optional string model_name = 3;
+
+ // Type of widget that was involved in triggering this event.
+ optional android.stats.textclassifier.WidgetType widget_type = 4;
+
+ // Detected language.
+ optional string language_tag = 5;
+
+ // Score of the detected language.
+ optional float score = 6;
+
+ // Position of this action.
+ optional int32 action_index = 7;
+
+ // Name of source package.
+ optional string package_name = 8;
+}
+
+/**
+ * Information about an OTA update attempt by update_engine.
+ * Logged from platform/system/update_engine/metrics_reporter_android.cc
+ */
+message UpdateEngineUpdateAttemptReported {
+ // The number of attempts for the update engine to apply a given payload.
+ optional int32 attempt_number = 1;
+
+ optional android.stats.otaupdate.PayloadType payload_type = 2;
+
+ // The total time in minutes for the update engine to apply a given payload.
+ // The time is calculated by calling clock_gettime() / CLOCK_BOOTTIME; and
+ // it's increased when the system is sleeping.
+ optional int32 duration_boottime_in_minutes = 3;
+
+ // The total time in minutes for the update engine to apply a given payload.
+ // The time is calculated by calling clock_gettime() / CLOCK_MONOTONIC_RAW;
+ // and it's not increased when the system is sleeping.
+ optional int32 duration_monotonic_in_minutes = 4;
+
+ // The size of the payload in MiBs.
+ optional int32 payload_size_mib = 5;
+
+ // The attempt result reported by the update engine for an OTA update.
+ optional android.stats.otaupdate.AttemptResult attempt_result = 6;
+
+ // The error code reported by the update engine after an OTA update attempt
+ // on A/B devices.
+ optional android.stats.otaupdate.ErrorCode error_code = 7;
+
+ // The build fingerprint of the source system. The value is read from a
+ // system property when the device takes the update. e.g.
+ // Android/aosp_sailfish/sailfish:10/QP1A.190425.004/5507117:userdebug/test-keys
+ optional string source_fingerprint = 8;
+}
+
+/**
+ * Information about all the attempts the device make before finishing the
+ * successful update.
+ * Logged from platform/system/update_engine/metrics_reporter_android.cc
+ */
+message UpdateEngineSuccessfulUpdateReported {
+ // The number of attempts for the update engine to apply the payload for a
+ // successful update.
+ optional int32 attempt_count = 1;
+
+ optional android.stats.otaupdate.PayloadType payload_type = 2;
+
+ optional int32 payload_size_mib = 3;
+
+ // The total number of bytes downloaded by update_engine since the last
+ // successful update.
+ optional int32 total_bytes_downloaded_mib = 4;
+
+ // The ratio in percentage of the over-downloaded bytes compared to the
+ // total bytes needed to successfully install the update. e.g. 200 if we
+ // download 200MiB in total for a 100MiB package.
+ optional int32 download_overhead_percentage = 5;
+
+ // The total time in minutes for the update engine to apply the payload for a
+ // successful update.
+ optional int32 total_duration_minutes = 6;
+
+ // The number of reboot of the device during a successful update.
+ optional int32 reboot_count = 7;
+}
+
+/**
+ * Global display pipeline metrics reported by SurfaceFlinger.
+ * Pulled from:
+ * frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
+ */
+message SurfaceflingerStatsGlobalInfo {
+ // Total number of frames presented during the tracing period
+ optional int64 total_frames = 1;
+ // Total number of frames missed
+ optional int64 missed_frames = 2;
+ // Total number of frames that fell back to client composition
+ optional int64 client_composition_frames = 3;
+ // Total time the display was turned on
+ optional int64 display_on_millis = 4;
+ // Total time that was spent performing animations.
+ // This is derived from the present-to-present layer histogram
+ optional int64 animation_millis = 5;
+}
+
+/**
+ * Per-layer display pipeline metrics reported by SurfaceFlinger.
+ * The number of layers uploaded will be restricted due to size limitations.
+ * Pulled from:
+ * frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
+ */
+message SurfaceflingerStatsLayerInfo {
+ // The layer for this set of metrics
+ // For now we can infer that the package name is included in the layer
+ // name.
+ optional string layer_name = 1;
+ // Total number of frames presented
+ optional int64 total_frames = 2;
+ // Total number of dropped frames while latching a buffer for this layer.
+ optional int64 dropped_frames = 3;
+ // Set of timings measured between successive presentation timestamps.
+ optional FrameTimingHistogram present_to_present = 4
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Set of timings measured from when an app queued a buffer for
+ // presentation, until the buffer was actually presented to the
+ // display.
+ optional FrameTimingHistogram post_to_present = 5
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Set of timings measured from when a buffer is ready to be presented,
+ // until the buffer was actually presented to the display.
+ optional FrameTimingHistogram acquire_to_present = 6
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Set of timings measured from when a buffer was latched by
+ // SurfaceFlinger, until the buffer was presented to the display
+ optional FrameTimingHistogram latch_to_present = 7
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Set of timings measured from the desired presentation to the actual
+ // presentation time
+ optional FrameTimingHistogram desired_to_present = 8
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Set of timings measured from when an app queued a buffer for
+ // presentation, until the buffer was ready to be presented.
+ optional FrameTimingHistogram post_to_acquire = 9
+ [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Histogram of frame counts bucketed by time in milliseconds.
+ * Because of size limitations, we hard-cap the number of buckets, with
+ * buckets for corresponding to larger milliseconds being less precise.
+ */
+message FrameTimingHistogram {
+ // Timings in milliseconds that describes a set of histogram buckets
+ repeated int32 time_millis_buckets = 1;
+ // Number of frames that match to each time_millis, i.e. the bucket
+ // contents
+ // It's required that len(time_millis) == len(frame_count)
+ repeated int64 frame_counts = 2;
+}
+
+/**
+ * Information about camera facing and API level usage.
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/camera/CameraServiceProxy.java
+ */
+message CameraActionEvent {
+ // Camera session duration
+ optional int64 duration = 1;
+
+ // Camera API level used
+ optional int32 api_level = 2;
+
+ // Name of client package
+ optional string package_name = 3;
+
+ // Camera facing
+ enum Facing {
+ UNKNOWN = 0;
+ BACK = 1;
+ FRONT = 2;
+ EXTERNAL = 3;
+ }
+ optional Facing facing = 4;
+}
+
+/**
* Logs when a compatibility change is affecting an app.
*
* Logged from:
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 60a4b236df11..52a1269798ca 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -110,20 +110,14 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf
void CombinationConditionTracker::isConditionMet(
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
- const std::vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
const bool isPartialLink,
- vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
+ vector<ConditionState>& conditionCache) const {
// So far, this is fine as there is at most one child having sliced output.
for (const int childIndex : mChildren) {
if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
allConditions[childIndex]->isConditionMet(conditionParameters, allConditions,
- dimensionFields,
- isSubOutputDimensionFields,
isPartialLink,
- conditionCache,
- dimensionsKeySet);
+ conditionCache);
}
}
conditionCache[mIndex] =
@@ -178,25 +172,6 @@ void CombinationConditionTracker::evaluateCondition(
}
}
-ConditionState CombinationConditionTracker::getMetConditionDimension(
- const std::vector<sp<ConditionTracker>>& allConditions,
- const std::vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
- vector<ConditionState> conditionCache(allConditions.size(), ConditionState::kNotEvaluated);
- // So far, this is fine as there is at most one child having sliced output.
- for (const int childIndex : mChildren) {
- conditionCache[childIndex] = conditionCache[childIndex] |
- allConditions[childIndex]->getMetConditionDimension(
- allConditions, dimensionFields, isSubOutputDimensionFields, dimensionsKeySet);
- }
- evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
- if (conditionCache[mIndex] == ConditionState::kTrue && dimensionsKeySet.empty()) {
- dimensionsKeySet.insert(DEFAULT_DIMENSION_KEY);
- }
- return conditionCache[mIndex];
-}
-
bool CombinationConditionTracker::equalOutputDimensions(
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensions) const {
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 481cb200d8e6..e3d860127780 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -43,17 +43,8 @@ public:
void isConditionMet(const ConditionKey& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
const bool isPartialLink,
- std::vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
-
- ConditionState getMetConditionDimension(
- const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
+ std::vector<ConditionState>& conditionCache) const override;
// Only one child predicate can have dimension.
const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 1f4266b61cdf..e94ea6586f05 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -84,29 +84,14 @@ public:
// condition.
// [allConditions]: all condition trackers. This is needed because the condition evaluation is
// done recursively
- // [dimensionFields]: the needed dimension fields which should be all or subset of the condition
- // tracker output dimension.
- // [isSubOutputDimensionFields]: true if the needed dimension fields which is strictly subset of
- // the condition tracker output dimension.
// [isPartialLink]: true if the link specified by 'conditionParameters' contains all the fields
// in the condition tracker output dimension.
// [conditionCache]: the cache holding the condition evaluation values.
- // [dimensionsKeySet]: the dimensions where the sliced condition is true. For combination
- // condition, it assumes that only one child predicate is sliced.
virtual void isConditionMet(
const ConditionKey& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
const bool isPartialLink,
- std::vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const = 0;
-
- virtual ConditionState getMetConditionDimension(
- const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const = 0;
+ std::vector<ConditionState>& conditionCache) const = 0;
// return the list of LogMatchingTracker index that this ConditionTracker uses.
virtual const std::set<int>& getLogTrackerIndex() const {
diff --git a/cmds/statsd/src/condition/ConditionWizard.cpp b/cmds/statsd/src/condition/ConditionWizard.cpp
index 23a9d371145e..4f44a69ba980 100644
--- a/cmds/statsd/src/condition/ConditionWizard.cpp
+++ b/cmds/statsd/src/condition/ConditionWizard.cpp
@@ -25,27 +25,15 @@ using std::string;
using std::vector;
ConditionState ConditionWizard::query(const int index, const ConditionKey& parameters,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- const bool isPartialLink,
- std::unordered_set<HashableDimensionKey>* dimensionKeySet) {
+ const bool isPartialLink) {
vector<ConditionState> cache(mAllConditions.size(), ConditionState::kNotEvaluated);
mAllConditions[index]->isConditionMet(
- parameters, mAllConditions, dimensionFields, isSubOutputDimensionFields, isPartialLink,
- cache, *dimensionKeySet);
+ parameters, mAllConditions, isPartialLink,
+ cache);
return cache[index];
}
-ConditionState ConditionWizard::getMetConditionDimension(
- const int index, const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- std::unordered_set<HashableDimensionKey>* dimensionsKeySet) const {
- return mAllConditions[index]->getMetConditionDimension(mAllConditions, dimensionFields,
- isSubOutputDimensionFields,
- *dimensionsKeySet);
-}
-
const set<HashableDimensionKey>* ConditionWizard::getChangedToTrueDimensions(
const int index) const {
return mAllConditions[index]->getChangedToTrueDimensions(mAllConditions);
@@ -82,4 +70,4 @@ bool ConditionWizard::equalOutputDimensions(const int index, const vector<Matche
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
index 2c8814772839..892647910d9f 100644
--- a/cmds/statsd/src/condition/ConditionWizard.h
+++ b/cmds/statsd/src/condition/ConditionWizard.h
@@ -40,15 +40,7 @@ public:
// The ConditionTracker at [conditionIndex] can be a CombinationConditionTracker. In this case,
// the conditionParameters contains the parameters for it's children SimpleConditionTrackers.
virtual ConditionState query(const int conditionIndex, const ConditionKey& conditionParameters,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- const bool isPartialLink,
- std::unordered_set<HashableDimensionKey>* dimensionKeySet);
-
- virtual ConditionState getMetConditionDimension(
- const int index, const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- std::unordered_set<HashableDimensionKey>* dimensionsKeySet) const;
+ const bool isPartialLink);
virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(const int index) const;
virtual const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 87104a34c009..0c92149f4c96 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -344,11 +344,8 @@ void SimpleConditionTracker::evaluateCondition(
void SimpleConditionTracker::isConditionMet(
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
const bool isPartialLink,
- vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
+ vector<ConditionState>& conditionCache) const {
if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
// it has been evaluated.
@@ -360,18 +357,13 @@ void SimpleConditionTracker::isConditionMet(
if (pair == conditionParameters.end()) {
ConditionState conditionState = ConditionState::kNotEvaluated;
- if (dimensionFields.size() > 0 && dimensionFields[0].mMatcher.getTag() == mDimensionTag) {
- conditionState = conditionState | getMetConditionDimension(
- allConditions, dimensionFields, isSubOutputDimensionFields, dimensionsKeySet);
- } else {
- conditionState = conditionState | mInitialValue;
- if (!mSliced) {
- const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
- if (itr != mSlicedConditionState.end()) {
- ConditionState sliceState =
- itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
- conditionState = conditionState | sliceState;
- }
+ conditionState = conditionState | mInitialValue;
+ if (!mSliced) {
+ const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
+ if (itr != mSlicedConditionState.end()) {
+ ConditionState sliceState =
+ itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
+ conditionState = conditionState | sliceState;
}
}
conditionCache[mIndex] = conditionState;
@@ -389,15 +381,6 @@ void SimpleConditionTracker::isConditionMet(
slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
if (slice.first.contains(key)) {
conditionState = conditionState | sliceState;
- if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
- if (isSubOutputDimensionFields) {
- HashableDimensionKey dimensionKey;
- filterValues(dimensionFields, slice.first.getValues(), &dimensionKey);
- dimensionsKeySet.insert(dimensionKey);
- } else {
- dimensionsKeySet.insert(slice.first);
- }
- }
}
}
} else {
@@ -407,15 +390,6 @@ void SimpleConditionTracker::isConditionMet(
ConditionState sliceState =
startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
conditionState = conditionState | sliceState;
- if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
- if (isSubOutputDimensionFields) {
- HashableDimensionKey dimensionKey;
- filterValues(dimensionFields, startedCountIt->first.getValues(), &dimensionKey);
- dimensionsKeySet.insert(dimensionKey);
- } else {
- dimensionsKeySet.insert(startedCountIt->first);
- }
- }
}
}
@@ -423,41 +397,6 @@ void SimpleConditionTracker::isConditionMet(
VLOG("Predicate %lld return %d", (long long)mConditionId, conditionCache[mIndex]);
}
-ConditionState SimpleConditionTracker::getMetConditionDimension(
- const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
- ConditionState conditionState = mInitialValue;
- if (dimensionFields.size() == 0 || mOutputDimensions.size() == 0 ||
- dimensionFields[0].mMatcher.getTag() != mOutputDimensions[0].mMatcher.getTag()) {
- const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
- if (itr != mSlicedConditionState.end()) {
- ConditionState sliceState =
- itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
- conditionState = conditionState | sliceState;
- }
- return conditionState;
- }
-
- for (const auto& slice : mSlicedConditionState) {
- ConditionState sliceState =
- slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
- conditionState = conditionState | sliceState;
-
- if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
- if (isSubOutputDimensionFields) {
- HashableDimensionKey dimensionKey;
- filterValues(dimensionFields, slice.first.getValues(), &dimensionKey);
- dimensionsKeySet.insert(dimensionKey);
- } else {
- dimensionsKeySet.insert(slice.first);
- }
- }
- }
- return conditionState;
-}
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index 47d1eceb9022..5c5cc565f783 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -48,17 +48,8 @@ public:
void isConditionMet(const ConditionKey& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
const bool isPartialLink,
- std::vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
-
- ConditionState getMetConditionDimension(
- const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
+ std::vector<ConditionState>& conditionCache) const override;
virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
const std::vector<sp<ConditionTracker>>& allConditions) const {
diff --git a/cmds/statsd/src/condition/StateTracker.cpp b/cmds/statsd/src/condition/StateConditionTracker.cpp
index 1965ce6015ff..7f3eeddba831 100644
--- a/cmds/statsd/src/condition/StateTracker.cpp
+++ b/cmds/statsd/src/condition/StateConditionTracker.cpp
@@ -16,7 +16,7 @@
#define DEBUG false // STOPSHIP if true
#include "Log.h"
-#include "StateTracker.h"
+#include "StateConditionTracker.h"
#include "guardrail/StatsdStats.h"
namespace android {
@@ -27,7 +27,7 @@ using std::string;
using std::unordered_set;
using std::vector;
-StateTracker::StateTracker(const ConfigKey& key, const int64_t& id, const int index,
+StateConditionTracker::StateConditionTracker(const ConfigKey& key, const int64_t& id, const int index,
const SimplePredicate& simplePredicate,
const unordered_map<int64_t, int>& trackerNameIndexMap,
const vector<Matcher> primaryKeys)
@@ -69,19 +69,19 @@ StateTracker::StateTracker(const ConfigKey& key, const int64_t& id, const int in
mInitialized = true;
}
-StateTracker::~StateTracker() {
- VLOG("~StateTracker()");
+StateConditionTracker::~StateConditionTracker() {
+ VLOG("~StateConditionTracker()");
}
-bool StateTracker::init(const vector<Predicate>& allConditionConfig,
+bool StateConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<int64_t, int>& conditionIdIndexMap,
vector<bool>& stack) {
return mInitialized;
}
-void StateTracker::dumpState() {
- VLOG("StateTracker %lld DUMP:", (long long)mConditionId);
+void StateConditionTracker::dumpState() {
+ VLOG("StateConditionTracker %lld DUMP:", (long long)mConditionId);
for (const auto& value : mSlicedState) {
VLOG("\t%s -> %s", value.first.toString().c_str(), value.second.toString().c_str());
}
@@ -95,7 +95,7 @@ void StateTracker::dumpState() {
}
}
-bool StateTracker::hitGuardRail(const HashableDimensionKey& newKey) {
+bool StateConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) {
if (mSlicedState.find(newKey) != mSlicedState.end()) {
// if the condition is not sliced or the key is not new, we are good!
return false;
@@ -114,7 +114,7 @@ bool StateTracker::hitGuardRail(const HashableDimensionKey& newKey) {
return false;
}
-void StateTracker::evaluateCondition(const LogEvent& event,
+void StateConditionTracker::evaluateCondition(const LogEvent& event,
const vector<MatchingState>& eventMatcherValues,
const vector<sp<ConditionTracker>>& mAllConditions,
vector<ConditionState>& conditionCache,
@@ -135,7 +135,7 @@ void StateTracker::evaluateCondition(const LogEvent& event,
return;
}
- VLOG("StateTracker evaluate event %s", event.ToString().c_str());
+ VLOG("StateConditionTracker evaluate event %s", event.ToString().c_str());
// Primary key can exclusive fields must be simple fields. so there won't be more than
// one keys matched.
@@ -151,7 +151,7 @@ void StateTracker::evaluateCondition(const LogEvent& event,
}
hitGuardRail(primaryKey);
- VLOG("StateTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str());
+ VLOG("StateConditionTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str());
auto it = mSlicedState.find(primaryKey);
if (it == mSlicedState.end()) {
@@ -176,13 +176,10 @@ void StateTracker::evaluateCondition(const LogEvent& event,
return;
}
-void StateTracker::isConditionMet(
+void StateConditionTracker::isConditionMet(
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
const bool isPartialLink,
- vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
+ vector<ConditionState>& conditionCache) const {
if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
// it has been evaluated.
VLOG("Yes, already evaluated, %lld %d", (long long)mConditionId, conditionCache[mIndex]);
@@ -193,10 +190,6 @@ void StateTracker::isConditionMet(
if (pair == conditionParameters.end()) {
if (mSlicedState.size() > 0) {
conditionCache[mIndex] = ConditionState::kTrue;
-
- for (const auto& state : mSlicedState) {
- dimensionsKeySet.insert(state.second);
- }
} else {
conditionCache[mIndex] = ConditionState::kUnknown;
}
@@ -208,25 +201,9 @@ void StateTracker::isConditionMet(
auto it = mSlicedState.find(primaryKey);
if (it != mSlicedState.end()) {
conditionCache[mIndex] = ConditionState::kTrue;
- dimensionsKeySet.insert(it->second);
- }
-}
-
-ConditionState StateTracker::getMetConditionDimension(
- const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
- if (mSlicedState.size() > 0) {
- for (const auto& state : mSlicedState) {
- dimensionsKeySet.insert(state.second);
- }
- return ConditionState::kTrue;
}
-
- return mInitialValue;
}
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/condition/StateTracker.h b/cmds/statsd/src/condition/StateConditionTracker.h
index 2bdf98c34c32..0efe1fb3fcb2 100644
--- a/cmds/statsd/src/condition/StateTracker.h
+++ b/cmds/statsd/src/condition/StateConditionTracker.h
@@ -25,14 +25,14 @@ namespace android {
namespace os {
namespace statsd {
-class StateTracker : public virtual ConditionTracker {
+class StateConditionTracker : public virtual ConditionTracker {
public:
- StateTracker(const ConfigKey& key, const int64_t& id, const int index,
+ StateConditionTracker(const ConfigKey& key, const int64_t& id, const int index,
const SimplePredicate& simplePredicate,
const std::unordered_map<int64_t, int>& trackerNameIndexMap,
const vector<Matcher> primaryKeys);
- ~StateTracker();
+ ~StateConditionTracker();
bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
@@ -46,8 +46,8 @@ public:
std::vector<bool>& changedCache) override;
/**
- * Note: dimensionFields will be ignored in StateTracker, because we demand metrics
- * must take the entire dimension fields from StateTracker. This is to make implementation
+ * Note: dimensionFields will be ignored in StateConditionTracker, because we demand metrics
+ * must take the entire dimension fields from StateConditionTracker. This is to make implementation
* simple and efficient.
*
* For example: wakelock duration by uid process states:
@@ -55,22 +55,8 @@ public:
*/
void isConditionMet(const ConditionKey& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
const bool isPartialLink,
- std::vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
-
- /**
- * Note: dimensionFields will be ignored in StateTracker, because we demand metrics
- * must take the entire dimension fields from StateTracker. This is to make implementation
- * simple and efficient.
- */
- ConditionState getMetConditionDimension(
- const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields,
- const bool isSubOutputDimensionFields,
- std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
+ std::vector<ConditionState>& conditionCache) const override;
virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
const std::vector<sp<ConditionTracker>>& allConditions) const {
@@ -123,9 +109,9 @@ private:
// maps from [primary_key] to [primary_key, exclusive_state].
std::unordered_map<HashableDimensionKey, HashableDimensionKey> mSlicedState;
- FRIEND_TEST(StateTrackerTest, TestStateChange);
+ FRIEND_TEST(StateConditionTrackerTest, TestStateChange);
};
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
index 0d3aca05e0e5..d38b87f046e0 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -92,10 +92,17 @@ static bool pullGpuStatsAppInfo(const sp<IGpuService>& gpuService,
android::util::GPU_STATS_APP_INFO, getWallClockNs(), getElapsedRealtimeNs());
if (!event->write(info.appPackageName)) return false;
if (!event->write((int64_t)info.driverVersionCode)) return false;
- if (!event->write(int64VectorToProtoByteString(info.glDriverLoadingTime))) return false;
- if (!event->write(int64VectorToProtoByteString(info.vkDriverLoadingTime))) return false;
- if (!event->write(int64VectorToProtoByteString(info.angleDriverLoadingTime))) return false;
+ if (!event->writeBytes(int64VectorToProtoByteString(info.glDriverLoadingTime))) {
+ return false;
+ }
+ if (!event->writeBytes(int64VectorToProtoByteString(info.vkDriverLoadingTime))) {
+ return false;
+ }
+ if (!event->writeBytes(int64VectorToProtoByteString(info.angleDriverLoadingTime))) {
+ return false;
+ }
if (!event->write(info.cpuVulkanInUse)) return false;
+ if (!event->write(info.falsePrerotation)) return false;
event->init();
data->emplace_back(event);
}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 69e6a11b9ad7..5a76d1f9c80d 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -17,12 +17,17 @@
#define DEBUG false
#include "Log.h"
+#include "StatsPullerManager.h"
+
#include <android/os/IStatsCompanionService.h>
#include <android/os/IStatsPullerCallback.h>
#include <cutils/log.h>
#include <math.h>
#include <stdint.h>
+
#include <algorithm>
+#include <iostream>
+
#include "../StatsService.h"
#include "../logd/LogEvent.h"
#include "../stats_log_util.h"
@@ -32,13 +37,11 @@
#include "ResourceHealthManagerPuller.h"
#include "StatsCallbackPuller.h"
#include "StatsCompanionServicePuller.h"
-#include "StatsPullerManager.h"
#include "SubsystemSleepStatePuller.h"
+#include "SurfaceflingerStatsPuller.h"
#include "TrainInfoPuller.h"
#include "statslog.h"
-#include <iostream>
-
using std::make_shared;
using std::map;
using std::shared_ptr;
@@ -143,17 +146,15 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
{.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}},
// process_memory_state
{android::util::PROCESS_MEMORY_STATE,
- {.additiveFields = {4, 5, 6, 7, 8, 9},
+ {.additiveFields = {4, 5, 6, 7, 8},
.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
- // native_process_memory_state
- {android::util::NATIVE_PROCESS_MEMORY_STATE,
- {.additiveFields = {3, 4, 5, 6, 8},
- .puller = new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}},
// process_memory_high_water_mark
{android::util::PROCESS_MEMORY_HIGH_WATER_MARK,
- {.additiveFields = {3},
- .puller =
+ {.puller =
new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
+ // process_memory_snapshot
+ {android::util::PROCESS_MEMORY_SNAPSHOT,
+ {.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_SNAPSHOT)}},
// system_ion_heap_size
{android::util::SYSTEM_ION_HEAP_SIZE,
{.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}},
@@ -267,6 +268,10 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// App ops
{android::util::APP_OPS,
{.puller = new StatsCompanionServicePuller(android::util::APP_OPS)}},
+ // SurfaceflingerStatsGlobalInfo
+ {android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ {.puller =
+ new SurfaceflingerStatsPuller(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp b/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp
new file mode 100644
index 000000000000..23b2236f35f2
--- /dev/null
+++ b/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 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 "SurfaceflingerStatsPuller.h"
+
+#include <cutils/compiler.h>
+
+#include <numeric>
+
+#include "logd/LogEvent.h"
+#include "stats_log_util.h"
+#include "statslog.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+SurfaceflingerStatsPuller::SurfaceflingerStatsPuller(const int tagId) : StatsPuller(tagId) {
+}
+
+bool SurfaceflingerStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) {
+ switch (mTagId) {
+ case android::util::SURFACEFLINGER_STATS_GLOBAL_INFO:
+ return pullGlobalInfo(data);
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static int64_t getTotalTime(
+ const google::protobuf::RepeatedPtrField<surfaceflinger::SFTimeStatsHistogramBucketProto>&
+ buckets) {
+ int64_t total = 0;
+ for (const auto& bucket : buckets) {
+ if (bucket.time_millis() == 1000) {
+ continue;
+ }
+
+ total += bucket.time_millis() * bucket.frame_count();
+ }
+
+ return total;
+}
+
+bool SurfaceflingerStatsPuller::pullGlobalInfo(std::vector<std::shared_ptr<LogEvent>>* data) {
+ std::string protoBytes;
+ if (CC_UNLIKELY(mStatsProvider)) {
+ protoBytes = mStatsProvider();
+ } else {
+ std::unique_ptr<FILE, decltype(&pclose)> pipe(popen("dumpsys SurfaceFlinger --timestats -dump --proto", "r"), pclose);
+ if (!pipe.get()) {
+ return false;
+ }
+ char buf[1024];
+ size_t bytesRead = 0;
+ do {
+ bytesRead = fread(buf, 1, sizeof(buf), pipe.get());
+ protoBytes.append(buf, bytesRead);
+ } while (bytesRead > 0);
+ }
+ surfaceflinger::SFTimeStatsGlobalProto proto;
+ proto.ParseFromString(protoBytes);
+
+ int64_t totalTime = getTotalTime(proto.present_to_present());
+
+ data->clear();
+ data->reserve(1);
+ std::shared_ptr<LogEvent> event =
+ make_shared<LogEvent>(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, getWallClockNs(),
+ getElapsedRealtimeNs());
+ if (!event->write(proto.total_frames())) return false;
+ if (!event->write(proto.missed_frames())) return false;
+ if (!event->write(proto.client_composition_frames())) return false;
+ if (!event->write(proto.display_on_time())) return false;
+ if (!event->write(totalTime)) return false;
+ event->init();
+ data->emplace_back(event);
+
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/SurfaceflingerStatsPuller.h b/cmds/statsd/src/external/SurfaceflingerStatsPuller.h
new file mode 100644
index 000000000000..ed7153edf797
--- /dev/null
+++ b/cmds/statsd/src/external/SurfaceflingerStatsPuller.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <timestatsproto/TimeStatsProtoHeader.h>
+
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Pull metrics from Surfaceflinger
+ */
+class SurfaceflingerStatsPuller : public StatsPuller {
+public:
+ explicit SurfaceflingerStatsPuller(const int tagId);
+
+ // StatsPuller interface
+ bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) override;
+
+protected:
+ // Test-only, for injecting fake data
+ using StatsProvider = std::function<std::string()>;
+ StatsProvider mStatsProvider;
+
+private:
+ bool pullGlobalInfo(std::vector<std::shared_ptr<LogEvent>>* data);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 0ade53118d77..fd19c9d61f87 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -332,6 +332,13 @@ bool LogEvent::write(float value) {
return false;
}
+bool LogEvent::writeBytes(const string& value) {
+ if (mContext) {
+ return android_log_write_char_array(mContext, value.c_str(), value.length()) >= 0;
+ }
+ return false;
+}
+
bool LogEvent::writeKeyValuePairs(int32_t uid,
const std::map<int32_t, int32_t>& int_map,
const std::map<int32_t, int64_t>& long_map,
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 531ce299beef..f1f45a2d3bc7 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -21,9 +21,9 @@
#include <android/frameworks/stats/1.0/types.h>
#include <android/os/StatsLogEventWrapper.h>
#include <android/util/ProtoOutputStream.h>
-#include <log/log_event_list.h>
#include <log/log_read.h>
#include <private/android_logger.h>
+#include <stats_event_list.h>
#include <utils/Errors.h>
#include <string>
@@ -157,6 +157,7 @@ public:
bool write(float value);
bool write(const std::vector<AttributionNodeInternal>& nodes);
bool write(const AttributionNodeInternal& node);
+ bool writeBytes(const std::string& value);
bool writeKeyValuePairs(int32_t uid,
const std::map<int32_t, int32_t>& int_map,
const std::map<int32_t, int64_t>& long_map,
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 8dc5cef988b0..476fae37899d 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -84,7 +84,7 @@ bool combinationMatch(const vector<int>& children, const LogicalOperation& opera
bool tryMatchString(const UidMap& uidMap, const Field& field, const Value& value,
const string& str_match) {
- if (isAttributionUidField(field, value)) {
+ if (isAttributionUidField(field, value) || isUidField(field, value)) {
int uid = value.int_value;
auto aidIt = UidMap::sAidToUidMapping.find(str_match);
if (aidIt != UidMap::sAidToUidMapping.end()) {
@@ -358,9 +358,10 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
bool matchesSimple(const UidMap& uidMap, const SimpleAtomMatcher& simpleMatcher,
const LogEvent& event) {
- if (simpleMatcher.field_value_matcher_size() <= 0) {
- return event.GetTagId() == simpleMatcher.atom_id();
+ if (event.GetTagId() != simpleMatcher.atom_id()) {
+ return false;
}
+
for (const auto& matcher : simpleMatcher.field_value_matcher()) {
if (!matchesSimple(uidMap, matcher, event.getValues(), 0, event.getValues().size(), 0)) {
return false;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index c023e6f77e7c..b5c8e35accad 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -37,6 +37,7 @@ using std::map;
using std::string;
using std::unordered_map;
using std::vector;
+using std::shared_ptr;
namespace android {
namespace os {
@@ -48,7 +49,6 @@ const int FIELD_ID_COUNT_METRICS = 5;
const int FIELD_ID_TIME_BASE = 9;
const int FIELD_ID_BUCKET_SIZE = 10;
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
-const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
const int FIELD_ID_IS_ACTIVE = 14;
// for CountMetricDataWrapper
@@ -68,8 +68,13 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric& metric,
const int conditionIndex,
const sp<ConditionWizard>& wizard,
- const int64_t timeBaseNs, const int64_t startTimeNs)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard) {
+ const int64_t timeBaseNs, const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>&
+ eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>&
+ eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap) {
if (metric.has_bucket()) {
mBucketSizeNs =
TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
@@ -82,12 +87,7 @@ CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric
mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
}
- mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
- HasPositionALL(metric.dimensions_in_condition());
-
- if (metric.has_dimensions_in_condition()) {
- translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
- }
+ mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
@@ -100,8 +100,6 @@ CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric
mConditionSliced = true;
}
- mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
-
flushIfNeededLocked(startTimeNs);
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
@@ -171,13 +169,6 @@ void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
protoOutput->end(dimenPathToken);
}
- if (!mDimensionsInCondition.empty()) {
- uint64_t dimenPathToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
- writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
- protoOutput->end(dimenPathToken);
- }
-
}
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
@@ -266,6 +257,7 @@ bool CountMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("CountMetric %lld dropping data for dimension key %s",
(long long)mMetricId, newKey.toString().c_str());
+ StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
return true;
}
}
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index b4a910c6f410..1cdc97668b1d 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -42,7 +42,11 @@ class CountMetricProducer : public MetricProducer {
public:
CountMetricProducer(const ConfigKey& key, const CountMetric& countMetric,
const int conditionIndex, const sp<ConditionWizard>& wizard,
- const int64_t timeBaseNs, const int64_t startTimeNs);
+ const int64_t timeBaseNs, const int64_t startTimeNs,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~CountMetricProducer();
@@ -102,6 +106,7 @@ private:
FRIEND_TEST(CountMetricProducerTest, TestEventWithAppUpgrade);
FRIEND_TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket);
FRIEND_TEST(CountMetricProducerTest, TestFirstBucket);
+ FRIEND_TEST(CountMetricProducerTest, TestOneWeekTimeUnit);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 96fbf7fb5ebe..31b90f3b13b1 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -36,6 +36,7 @@ using android::util::ProtoOutputStream;
using std::string;
using std::unordered_map;
using std::vector;
+using std::shared_ptr;
namespace android {
namespace os {
@@ -47,7 +48,6 @@ const int FIELD_ID_DURATION_METRICS = 6;
const int FIELD_ID_TIME_BASE = 9;
const int FIELD_ID_BUCKET_SIZE = 10;
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
-const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
const int FIELD_ID_IS_ACTIVE = 14;
// for DurationMetricDataWrapper
const int FIELD_ID_DATA = 1;
@@ -63,14 +63,15 @@ const int FIELD_ID_BUCKET_NUM = 4;
const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
-DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const DurationMetric& metric,
- const int conditionIndex, const size_t startIndex,
- const size_t stopIndex, const size_t stopAllIndex,
- const bool nesting,
- const sp<ConditionWizard>& wizard,
- const FieldMatcher& internalDimensions,
- const int64_t timeBaseNs, const int64_t startTimeNs)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
+DurationMetricProducer::DurationMetricProducer(
+ const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
+ const size_t startIndex, const size_t stopIndex, const size_t stopAllIndex,
+ const bool nesting, const sp<ConditionWizard>& wizard,
+ const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap),
mAggregationType(metric.aggregation_type()),
mStartIndex(startIndex),
mStopIndex(stopIndex),
@@ -100,12 +101,7 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat
ALOGE("Position ANY in dimension_in_what not supported.");
}
- if (metric.has_dimensions_in_condition()) {
- translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
- }
-
- mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
- HasPositionALL(metric.dimensions_in_condition());
+ mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
@@ -115,19 +111,16 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat
translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
mMetric2ConditionLinks.push_back(mc);
}
+ mConditionSliced = true;
}
- mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
mUnSlicedPartCondition = ConditionState::kUnknown;
mUseWhatDimensionAsInternalDimension = equalDimensions(mDimensionsInWhat, mInternalDimensions);
- if (mWizard != nullptr && mConditionTrackerIndex >= 0) {
- mSameConditionDimensionsInTracker =
- mWizard->equalOutputDimensions(mConditionTrackerIndex, mDimensionsInCondition);
- if (mMetric2ConditionLinks.size() == 1) {
- mHasLinksToAllConditionDimensionsInTracker =
- mWizard->equalOutputDimensions(mConditionTrackerIndex,
- mMetric2ConditionLinks.begin()->conditionFields);
- }
+ if (mWizard != nullptr && mConditionTrackerIndex >= 0 &&
+ mMetric2ConditionLinks.size() == 1) {
+ mHasLinksToAllConditionDimensionsInTracker =
+ mWizard->equalOutputDimensions(mConditionTrackerIndex,
+ mMetric2ConditionLinks.begin()->conditionFields);
}
flushIfNeededLocked(startTimeNs);
// Adjust start for partial bucket
@@ -164,13 +157,13 @@ unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
case DurationMetric_AggregationType_SUM:
return make_unique<OringDurationTracker>(
mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
- mDimensionsInCondition, mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
+ mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
mTimeBaseNs, mBucketSizeNs, mConditionSliced,
mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
case DurationMetric_AggregationType_MAX_SPARSE:
return make_unique<MaxDurationTracker>(
mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
- mDimensionsInCondition, mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
+ mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
mTimeBaseNs, mBucketSizeNs, mConditionSliced,
mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
}
@@ -178,13 +171,11 @@ unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
// SlicedConditionChange optimization case 1:
// 1. If combination condition, logical operation is AND, only one sliced child predicate.
-// 2. No condition in dimension
-// 3. The links covers all dimension fields in the sliced child condition predicate.
+// 2. The links covers all dimension fields in the sliced child condition predicate.
void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool condition,
const int64_t eventTime) {
if (mMetric2ConditionLinks.size() != 1 ||
- !mHasLinksToAllConditionDimensionsInTracker ||
- !mDimensionsInCondition.empty()) {
+ !mHasLinksToAllConditionDimensionsInTracker) {
return;
}
@@ -249,178 +240,20 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio
}
}
-
-// SlicedConditionChange optimization case 2:
-// 1. If combination condition, logical operation is AND, only one sliced child predicate.
-// 2. Has dimensions_in_condition and it equals to the output dimensions of the sliced predicate.
-void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt2(bool condition,
- const int64_t eventTime) {
- if (mMetric2ConditionLinks.size() > 1 || !mSameConditionDimensionsInTracker) {
- return;
- }
-
- auto dimensionsChangedToTrue = mWizard->getChangedToTrueDimensions(mConditionTrackerIndex);
- auto dimensionsChangedToFalse = mWizard->getChangedToFalseDimensions(mConditionTrackerIndex);
-
- bool currentUnSlicedPartCondition = true;
- if (!mWizard->IsSimpleCondition(mConditionTrackerIndex)) {
- ConditionState unslicedPartState =
- mWizard->getUnSlicedPartConditionState(mConditionTrackerIndex);
- // When the unsliced part is still false, return directly.
- if (mUnSlicedPartCondition == ConditionState::kFalse &&
- unslicedPartState == ConditionState::kFalse) {
- return;
- }
- mUnSlicedPartCondition = unslicedPartState;
- currentUnSlicedPartCondition = mUnSlicedPartCondition > 0;
- }
-
- const std::set<HashableDimensionKey>* trueDimensionsToProcess = nullptr;
- const std::set<HashableDimensionKey>* falseDimensionsToProcess = nullptr;
-
- std::set<HashableDimensionKey> currentTrueConditionDimensions;
- if (dimensionsChangedToTrue == nullptr || dimensionsChangedToFalse == nullptr ||
- (dimensionsChangedToTrue->empty() && dimensionsChangedToFalse->empty())) {
- mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, &currentTrueConditionDimensions);
- trueDimensionsToProcess = &currentTrueConditionDimensions;
- } else if (currentUnSlicedPartCondition) {
- // Handles the condition change from the sliced predicate. If the unsliced condition state
- // is not true, not need to do anything.
- trueDimensionsToProcess = dimensionsChangedToTrue;
- falseDimensionsToProcess = dimensionsChangedToFalse;
- }
-
- if (trueDimensionsToProcess == nullptr && falseDimensionsToProcess == nullptr) {
- return;
- }
-
- for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- if (falseDimensionsToProcess != nullptr) {
- for (const auto& changedDim : *falseDimensionsToProcess) {
- auto condIt = whatIt.second.find(changedDim);
- if (condIt != whatIt.second.end()) {
- condIt->second->onConditionChanged(false, eventTime);
- }
- }
- }
- if (trueDimensionsToProcess != nullptr) {
- HashableDimensionKey linkedConditionDimensionKey;
- if (!trueDimensionsToProcess->empty() && mMetric2ConditionLinks.size() == 1) {
- getDimensionForCondition(whatIt.first.getValues(),
- mMetric2ConditionLinks[0],
- &linkedConditionDimensionKey);
- }
- for (auto& trueDim : *trueDimensionsToProcess) {
- auto condIt = whatIt.second.find(trueDim);
- if (condIt != whatIt.second.end()) {
- condIt->second->onConditionChanged(
- currentUnSlicedPartCondition, eventTime);
- } else {
- if (mMetric2ConditionLinks.size() == 0 ||
- trueDim.contains(linkedConditionDimensionKey)) {
- if (!whatIt.second.empty()) {
- auto newEventKey = MetricDimensionKey(whatIt.first, trueDim);
- if (hitGuardRailLocked(newEventKey)) {
- continue;
- }
- unique_ptr<DurationTracker> newTracker =
- whatIt.second.begin()->second->clone(eventTime);
- if (newTracker != nullptr) {
- newTracker->setEventKey(newEventKey);
- newTracker->onConditionChanged(true, eventTime);
- whatIt.second[trueDim] = std::move(newTracker);
- }
- }
- }
- }
- }
- }
- }
-}
-
void DurationMetricProducer::onSlicedConditionMayChangeInternalLocked(bool overallCondition,
const int64_t eventTimeNs) {
bool changeDimTrackable = mWizard->IsChangedDimensionTrackable(mConditionTrackerIndex);
- if (changeDimTrackable && mHasLinksToAllConditionDimensionsInTracker &&
- mDimensionsInCondition.empty()) {
+ if (changeDimTrackable && mHasLinksToAllConditionDimensionsInTracker) {
onSlicedConditionMayChangeLocked_opt1(overallCondition, eventTimeNs);
return;
}
- if (changeDimTrackable && mSameConditionDimensionsInTracker &&
- mMetric2ConditionLinks.size() <= 1) {
- onSlicedConditionMayChangeLocked_opt2(overallCondition, eventTimeNs);
- return;
- }
-
// Now for each of the on-going event, check if the condition has changed for them.
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
for (auto& pair : whatIt.second) {
pair.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
}
}
-
- if (mDimensionsInCondition.empty()) {
- return;
- }
-
- if (mMetric2ConditionLinks.empty()) {
- std::unordered_set<HashableDimensionKey> conditionDimensionsKeySet;
- mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition,
- !mSameConditionDimensionsInTracker,
- &conditionDimensionsKeySet);
- for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (const auto& pair : whatIt.second) {
- conditionDimensionsKeySet.erase(pair.first);
- }
- }
- for (const auto& conditionDimension : conditionDimensionsKeySet) {
- for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- if (!whatIt.second.empty()) {
- auto newEventKey = MetricDimensionKey(whatIt.first, conditionDimension);
- if (hitGuardRailLocked(newEventKey)) {
- continue;
- }
- unique_ptr<DurationTracker> newTracker =
- whatIt.second.begin()->second->clone(eventTimeNs);
- if (newTracker != nullptr) {
- newTracker->setEventKey(MetricDimensionKey(newEventKey));
- newTracker->onSlicedConditionMayChange(overallCondition, eventTimeNs);
- whatIt.second[conditionDimension] = std::move(newTracker);
- }
- }
- }
- }
- } else {
- for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- ConditionKey conditionKey;
- for (const auto& link : mMetric2ConditionLinks) {
- getDimensionForCondition(whatIt.first.getValues(), link,
- &conditionKey[link.conditionId]);
- }
- std::unordered_set<HashableDimensionKey> conditionDimensionsKeys;
- mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
- !mSameConditionDimensionsInTracker,
- !mHasLinksToAllConditionDimensionsInTracker,
- &conditionDimensionsKeys);
-
- for (const auto& conditionDimension : conditionDimensionsKeys) {
- if (!whatIt.second.empty() &&
- whatIt.second.find(conditionDimension) == whatIt.second.end()) {
- auto newEventKey = MetricDimensionKey(whatIt.first, conditionDimension);
- if (hitGuardRailLocked(newEventKey)) {
- continue;
- }
- auto newTracker = whatIt.second.begin()->second->clone(eventTimeNs);
- if (newTracker != nullptr) {
- newTracker->setEventKey(newEventKey);
- newTracker->onSlicedConditionMayChange(overallCondition, eventTimeNs);
- whatIt.second[conditionDimension] = std::move(newTracker);
- }
- }
- }
- }
- }
}
void DurationMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
@@ -526,12 +359,6 @@ void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
protoOutput->end(dimenPathToken);
}
- if (!mDimensionsInCondition.empty()) {
- uint64_t dimenPathToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
- writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
- protoOutput->end(dimenPathToken);
- }
}
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
@@ -666,6 +493,7 @@ bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("DurationMetric %lld dropping data for condition dimension key %s",
(long long)mMetricId, newKey.getDimensionKeyInCondition().toString().c_str());
+ StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
return true;
}
}
@@ -679,6 +507,7 @@ bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("DurationMetric %lld dropping data for what dimension key %s",
(long long)mMetricId, newKey.getDimensionKeyInWhat().toString().c_str());
+ StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
return true;
}
}
@@ -790,52 +619,24 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
bool condition;
ConditionKey conditionKey;
- std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
if (mConditionSliced) {
for (const auto& link : mMetric2ConditionLinks) {
getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
}
auto conditionState =
- mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
- !mSameConditionDimensionsInTracker,
- !mHasLinksToAllConditionDimensionsInTracker,
- &dimensionKeysInCondition);
+ mWizard->query(mConditionTrackerIndex, conditionKey,
+ !mHasLinksToAllConditionDimensionsInTracker);
condition = conditionState == ConditionState::kTrue;
- if (mDimensionsInCondition.empty() && condition) {
- dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
- }
} else {
// TODO: The unknown condition state is not handled here, we should fix it.
condition = mCondition == ConditionState::kTrue;
- if (condition) {
- dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
- }
}
condition = condition && mIsActive;
- if (dimensionKeysInCondition.empty()) {
- handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY),
- conditionKey, condition, event);
- } else {
- auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
- // If the what dimension is already there, we should update all the trackers even
- // the condition is false.
- if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& condIt : whatIt->second) {
- const bool cond = dimensionKeysInCondition.find(condIt.first) !=
- dimensionKeysInCondition.end() && condition;
- handleStartEvent(MetricDimensionKey(dimensionInWhat, condIt.first),
- conditionKey, cond, event);
- dimensionKeysInCondition.erase(condIt.first);
- }
- }
- for (const auto& conditionDimension : dimensionKeysInCondition) {
- handleStartEvent(MetricDimensionKey(dimensionInWhat, conditionDimension), conditionKey,
- condition, event);
- }
- }
+ handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY),
+ conditionKey, condition, event);
}
size_t DurationMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 56c9fd68eac5..0592b1808f52 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -42,7 +42,12 @@ public:
const int conditionIndex, const size_t startIndex,
const size_t stopIndex, const size_t stopAllIndex, const bool nesting,
const sp<ConditionWizard>& wizard,
- const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs);
+ const FieldMatcher& internalDimensions, const int64_t timeBaseNs,
+ const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const unordered_map<int, vector<shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~DurationMetricProducer();
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 96133bd0a38d..a60a9161bdbb 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -36,6 +36,7 @@ using std::map;
using std::string;
using std::unordered_map;
using std::vector;
+using std::shared_ptr;
namespace android {
namespace os {
@@ -54,8 +55,13 @@ const int FIELD_ID_ATOMS = 2;
EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric& metric,
const int conditionIndex,
const sp<ConditionWizard>& wizard,
- const int64_t startTimeNs)
- : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
+ const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>&
+ eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>&
+ eventDeactivationMap)
+ : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap) {
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
Metric2Condition mc;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 74e6bc845c04..aab53c8b6816 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -35,7 +35,11 @@ class EventMetricProducer : public MetricProducer {
public:
EventMetricProducer(const ConfigKey& key, const EventMetric& eventMetric,
const int conditionIndex, const sp<ConditionWizard>& wizard,
- const int64_t startTimeNs);
+ const int64_t startTimeNs,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~EventMetricProducer();
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index a64bbc1056e0..e409b6fbb9e9 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -48,7 +48,6 @@ const int FIELD_ID_GAUGE_METRICS = 8;
const int FIELD_ID_TIME_BASE = 9;
const int FIELD_ID_BUCKET_SIZE = 10;
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
-const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
const int FIELD_ID_IS_ACTIVE = 14;
// for GaugeMetricDataWrapper
const int FIELD_ID_DATA = 1;
@@ -73,8 +72,11 @@ GaugeMetricProducer::GaugeMetricProducer(
const sp<ConditionWizard>& wizard, const int whatMatcherIndex,
const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int triggerAtomId,
const int atomId, const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
+ const sp<StatsPullerManager>& pullerManager,
+ const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
@@ -115,10 +117,6 @@ GaugeMetricProducer::GaugeMetricProducer(
mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
}
- if (metric.has_dimensions_in_condition()) {
- translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
- }
-
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
Metric2Condition mc;
@@ -127,10 +125,9 @@ GaugeMetricProducer::GaugeMetricProducer(
translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
mMetric2ConditionLinks.push_back(mc);
}
+ mConditionSliced = true;
}
- mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
- mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
- HasPositionALL(metric.dimensions_in_condition());
+ mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
flushIfNeededLocked(startTimeNs);
// Kicks off the puller immediately.
@@ -139,8 +136,11 @@ GaugeMetricProducer::GaugeMetricProducer(
mBucketSizeNs);
}
- // Adjust start for partial bucket
+ // Adjust start for partial first bucket and then pull if needed
mCurrentBucketStartTimeNs = startTimeNs;
+ if (mIsActive && mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
+ pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
+ }
VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d",
(long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs,
@@ -209,12 +209,6 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
protoOutput->end(dimenPathToken);
}
- if (!mDimensionsInCondition.empty()) {
- uint64_t dimenPathToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
- writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
- protoOutput->end(dimenPathToken);
- }
}
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
@@ -307,11 +301,6 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
}
}
-void GaugeMetricProducer::prepareFirstBucketLocked() {
- if (mIsActive && mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
- pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
- }
-}
void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
bool triggerPuller = false;
@@ -451,6 +440,7 @@ bool GaugeMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
if (newTupleCount > mDimensionHardLimit) {
ALOGE("GaugeMetric %lld dropping data for dimension key %s",
(long long)mMetricId, newKey.toString().c_str());
+ StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
return true;
}
}
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index a612adf8a38b..dfe1d56c61c7 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -58,11 +58,14 @@ class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDa
public:
GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
const int conditionIndex, const sp<ConditionWizard>& conditionWizard,
- const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard,
+ const int whatMatcherIndex,const sp<EventMatcherWizard>& matcherWizard,
const int pullTagId, const int triggerAtomId, const int atomId,
const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager);
+ const sp<StatsPullerManager>& pullerManager,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~GaugeMetricProducer();
@@ -125,8 +128,6 @@ private:
void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) override;
- void prepareFirstBucketLocked() override;
-
void pullAndMatchEventsLocked(const int64_t timestampNs);
const int mWhatMatcherIndex;
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 92752b29ecda..3426a195a748 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -40,6 +40,29 @@ const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1;
const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
+MetricProducer::MetricProducer(
+ const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
+ const int conditionIndex, const sp<ConditionWizard>& wizard,
+ const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap)
+ : mMetricId(metricId),
+ mConfigKey(key),
+ mTimeBaseNs(timeBaseNs),
+ mCurrentBucketStartTimeNs(timeBaseNs),
+ mCurrentBucketNum(0),
+ mCondition(initialCondition(conditionIndex)),
+ mConditionTrackerIndex(conditionIndex),
+ mConditionSliced(false),
+ mWizard(wizard),
+ mContainANYPositionInDimensionsInWhat(false),
+ mSliceByPositionALL(false),
+ mHasLinksToAllConditionDimensionsInTracker(false),
+ mEventActivationMap(eventActivationMap),
+ mEventDeactivationMap(eventDeactivationMap),
+ mIsActive(mEventActivationMap.empty()) {
+ }
+
void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
if (!mIsActive) {
return;
@@ -52,38 +75,24 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
bool condition;
ConditionKey conditionKey;
- std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
if (mConditionSliced) {
for (const auto& link : mMetric2ConditionLinks) {
getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
}
auto conditionState =
- mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
- !mSameConditionDimensionsInTracker,
- !mHasLinksToAllConditionDimensionsInTracker,
- &dimensionKeysInCondition);
+ mWizard->query(mConditionTrackerIndex, conditionKey,
+ !mHasLinksToAllConditionDimensionsInTracker);
condition = (conditionState == ConditionState::kTrue);
} else {
// TODO: The unknown condition state is not handled here, we should fix it.
condition = mCondition == ConditionState::kTrue;
}
- if (mDimensionsInCondition.empty() && condition) {
- dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
- }
-
HashableDimensionKey dimensionInWhat;
filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY);
- for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
- metricKey.setDimensionKeyInCondition(conditionDimensionKey);
- onMatchedLogEventInternalLocked(
- matcherIndex, metricKey, conditionKey, condition, event);
- }
- if (dimensionKeysInCondition.empty()) {
- onMatchedLogEventInternalLocked(
- matcherIndex, metricKey, conditionKey, condition, event);
- }
+ onMatchedLogEventInternalLocked(
+ matcherIndex, metricKey, conditionKey, condition, event);
}
bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
@@ -111,24 +120,6 @@ void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
}
}
-void MetricProducer::addActivation(int activationTrackerIndex, const ActivationType& activationType,
- int64_t ttl_seconds, int deactivationTrackerIndex) {
- std::lock_guard<std::mutex> lock(mMutex);
- // When a metric producer does not depend on any activation, its mIsActive is true.
- // Therefore, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
- // change.
- if (mEventActivationMap.empty()) {
- mIsActive = false;
- }
- std::shared_ptr<Activation> activation =
- std::make_shared<Activation>(activationType, ttl_seconds * NS_PER_SEC);
- mEventActivationMap.emplace(activationTrackerIndex, activation);
- if (-1 != deactivationTrackerIndex) {
- auto& deactivationList = mEventDeactivationMap[deactivationTrackerIndex];
- deactivationList.push_back(activation);
- }
-}
-
void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
auto it = mEventActivationMap.find(activationTrackerIndex);
if (it == mEventActivationMap.end()) {
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 09ad2903fa4c..1e1eb69aa8f0 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -69,6 +69,19 @@ enum DumpLatency {
NO_TIME_CONSTRAINTS = 2
};
+struct Activation {
+ Activation(const ActivationType& activationType, const int64_t ttlNs)
+ : ttl_ns(ttlNs),
+ start_ns(0),
+ state(ActivationState::kNotActive),
+ activationType(activationType) {}
+
+ const int64_t ttl_ns;
+ int64_t start_ns;
+ ActivationState state;
+ const ActivationType activationType;
+};
+
// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
// writing the report to dropbox. MetricProducers should respond to package changes as required in
// PackageInfoListener, but if none of the metrics are slicing by package name, then the update can
@@ -76,22 +89,10 @@ enum DumpLatency {
class MetricProducer : public virtual PackageInfoListener {
public:
MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
- const int conditionIndex, const sp<ConditionWizard>& wizard)
- : mMetricId(metricId),
- mConfigKey(key),
- mTimeBaseNs(timeBaseNs),
- mCurrentBucketStartTimeNs(timeBaseNs),
- mCurrentBucketNum(0),
- mCondition(initialCondition(conditionIndex)),
- mConditionSliced(false),
- mWizard(wizard),
- mConditionTrackerIndex(conditionIndex),
- mContainANYPositionInDimensionsInWhat(false),
- mSliceByPositionALL(false),
- mSameConditionDimensionsInTracker(false),
- mHasLinksToAllConditionDimensionsInTracker(false),
- mIsActive(true) {
- }
+ const int conditionIndex, const sp<ConditionWizard>& wizard,
+ const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap);
virtual ~MetricProducer(){};
@@ -168,11 +169,6 @@ public:
return clearPastBucketsLocked(dumpTimeNs);
}
- void dumpStates(FILE* out, bool verbose) const {
- std::lock_guard<std::mutex> lock(mMutex);
- dumpStatesLocked(out, verbose);
- }
-
// Returns the memory in bytes currently used to store this metric's data. Does not change
// state.
size_t byteSize() const {
@@ -180,34 +176,9 @@ public:
return byteSizeLocked();
}
- /* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */
- virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
- const sp<AlarmMonitor>& anomalyAlarmMonitor) {
- std::lock_guard<std::mutex> lock(mMutex);
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
- if (anomalyTracker != nullptr) {
- mAnomalyTrackers.push_back(anomalyTracker);
- }
- return anomalyTracker;
- }
-
- int64_t getBuckeSizeInNs() const {
- std::lock_guard<std::mutex> lock(mMutex);
- return mBucketSizeNs;
- }
-
- // Only needed for unit-testing to override guardrail.
- void setBucketSize(int64_t bucketSize) {
- mBucketSizeNs = bucketSize;
- }
-
- inline const int64_t& getMetricId() const {
- return mMetricId;
- }
-
- void loadActiveMetric(const ActiveMetric& activeMetric, int64_t currentTimeNs) {
+ void dumpStates(FILE* out, bool verbose) const {
std::lock_guard<std::mutex> lock(mMutex);
- loadActiveMetricLocked(activeMetric, currentTimeNs);
+ dumpStatesLocked(out, verbose);
}
// Let MetricProducer drop in-memory data to save memory.
@@ -219,9 +190,9 @@ public:
dropDataLocked(dropTimeNs);
}
- // For test only.
- inline int64_t getCurrentBucketNum() const {
- return mCurrentBucketNum;
+ void loadActiveMetric(const ActiveMetric& activeMetric, int64_t currentTimeNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ loadActiveMetricLocked(activeMetric, currentTimeNs);
}
void activate(int activationTrackerIndex, int64_t elapsedTimestampNs) {
@@ -239,44 +210,38 @@ public:
return isActiveLocked();
}
- void addActivation(int activationTrackerIndex, const ActivationType& activationType,
- int64_t ttl_seconds, int deactivationTrackerIndex = -1);
-
- void prepareFirstBucket() {
- std::lock_guard<std::mutex> lock(mMutex);
- prepareFirstBucketLocked();
- }
-
void flushIfExpire(int64_t elapsedTimestampNs);
void writeActiveMetricToProtoOutputStream(
int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);
-protected:
- virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
- virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
- const int64_t eventTime) = 0;
- virtual void onDumpReportLocked(const int64_t dumpTimeNs,
- const bool include_current_partial_bucket,
- const bool erase_data,
- const DumpLatency dumpLatency,
- std::set<string> *str_set,
- android::util::ProtoOutputStream* protoOutput) = 0;
- virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
- virtual size_t byteSizeLocked() const = 0;
- virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
-
- bool evaluateActiveStateLocked(int64_t elapsedTimestampNs);
- void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
- void cancelEventActivationLocked(int deactivationTrackerIndex);
+ // Start: getters/setters
+ inline const int64_t& getMetricId() const {
+ return mMetricId;
+ }
- inline bool isActiveLocked() const {
- return mIsActive;
+ // For test only.
+ inline int64_t getCurrentBucketNum() const {
+ return mCurrentBucketNum;
}
- void loadActiveMetricLocked(const ActiveMetric& activeMetric, int64_t currentTimeNs);
+ int64_t getBucketSizeInNs() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mBucketSizeNs;
+ }
- virtual void prepareFirstBucketLocked() {};
+ /* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */
+ virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
+ if (anomalyTracker != nullptr) {
+ mAnomalyTrackers.push_back(anomalyTracker);
+ }
+ return anomalyTracker;
+ }
+ // End: getters/setters
+protected:
/**
* Flushes the current bucket if the eventTime is after the current bucket's end time. This will
also flush the current partial bucket in memory.
@@ -284,14 +249,6 @@ protected:
virtual void flushIfNeededLocked(const int64_t& eventTime){};
/**
- * Flushes all the data including the current partial bucket.
- */
- virtual void flushLocked(const int64_t& eventTimeNs) {
- flushIfNeededLocked(eventTimeNs);
- flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
- };
-
- /**
* For metrics that aggregate (ie, every metric producer except for EventMetricProducer),
* we need to be able to flush the current buckets on demand (ie, end the current bucket and
* start new bucket). If this function is called when eventTimeNs is greater than the current
@@ -304,12 +261,65 @@ protected:
virtual void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) {};
+ /**
+ * Flushes all the data including the current partial bucket.
+ */
+ virtual void flushLocked(const int64_t& eventTimeNs) {
+ flushIfNeededLocked(eventTimeNs);
+ flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
+ };
+
+ /*
+ * Individual metrics can implement their own business logic here. All pre-processing is done.
+ *
+ * [matcherIndex]: the index of the matcher which matched this event. This is interesting to
+ * DurationMetric, because it has start/stop/stop_all 3 matchers.
+ * [eventKey]: the extracted dimension key for the final output. if the metric doesn't have
+ * dimensions, it will be DEFAULT_DIMENSION_KEY
+ * [conditionKey]: the keys of conditions which should be used to query the condition for this
+ * target event (from MetricConditionLink). This is passed to individual metrics
+ * because DurationMetric needs it to be cached.
+ * [condition]: whether condition is met. If condition is sliced, this is the result coming from
+ * query with ConditionWizard; If condition is not sliced, this is the
+ * nonSlicedCondition.
+ * [event]: the log event, just in case the metric needs its data, e.g., EventMetric.
+ */
+ virtual void onMatchedLogEventInternalLocked(
+ const size_t matcherIndex, const MetricDimensionKey& eventKey,
+ const ConditionKey& conditionKey, bool condition,
+ const LogEvent& event) = 0;
+
+ // Consume the parsed stats log entry that already matched the "what" of the metric.
+ virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
+ virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
+ virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
+ const int64_t eventTime) = 0;
+ virtual void onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
+ const bool erase_data,
+ const DumpLatency dumpLatency,
+ std::set<string> *str_set,
+ android::util::ProtoOutputStream* protoOutput) = 0;
+ virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
+ virtual size_t byteSizeLocked() const = 0;
+ virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
+ virtual void dropDataLocked(const int64_t dropTimeNs) = 0;
+ void loadActiveMetricLocked(const ActiveMetric& activeMetric, int64_t currentTimeNs);
+ void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
+ void cancelEventActivationLocked(int deactivationTrackerIndex);
+
+ bool evaluateActiveStateLocked(int64_t elapsedTimestampNs);
+
virtual void onActiveStateChangedLocked(const int64_t& eventTimeNs) {
if (!mIsActive) {
flushLocked(eventTimeNs);
}
}
+ inline bool isActiveLocked() const {
+ return mIsActive;
+ }
+
// Convenience to compute the current bucket's end time, which is always aligned with the
// start time of the metric.
int64_t getCurrentBucketEndTimeNs() const {
@@ -320,8 +330,6 @@ protected:
return (endNs - mTimeBaseNs) / mBucketSizeNs - 1;
}
- virtual void dropDataLocked(const int64_t dropTimeNs) = 0;
-
const int64_t mMetricId;
const ConfigKey mConfigKey;
@@ -342,21 +350,17 @@ protected:
ConditionState mCondition;
+ int mConditionTrackerIndex;
+
bool mConditionSliced;
sp<ConditionWizard> mWizard;
- int mConditionTrackerIndex;
-
- vector<Matcher> mDimensionsInWhat; // The dimensions_in_what defined in statsd_config
- vector<Matcher> mDimensionsInCondition; // The dimensions_in_condition defined in statsd_config
-
bool mContainANYPositionInDimensionsInWhat;
+
bool mSliceByPositionALL;
- // True iff the condition dimensions equal to the sliced dimensions in the simple condition
- // tracker. This field is always false for combinational condition trackers.
- bool mSameConditionDimensionsInTracker;
+ vector<Matcher> mDimensionsInWhat; // The dimensions_in_what defined in statsd_config
// True iff the metric to condition links cover all dimension fields in the condition tracker.
// This field is always false for combinational condition trackers.
@@ -366,43 +370,8 @@ protected:
std::vector<sp<AnomalyTracker>> mAnomalyTrackers;
- /*
- * Individual metrics can implement their own business logic here. All pre-processing is done.
- *
- * [matcherIndex]: the index of the matcher which matched this event. This is interesting to
- * DurationMetric, because it has start/stop/stop_all 3 matchers.
- * [eventKey]: the extracted dimension key for the final output. if the metric doesn't have
- * dimensions, it will be DEFAULT_DIMENSION_KEY
- * [conditionKey]: the keys of conditions which should be used to query the condition for this
- * target event (from MetricConditionLink). This is passed to individual metrics
- * because DurationMetric needs it to be cached.
- * [condition]: whether condition is met. If condition is sliced, this is the result coming from
- * query with ConditionWizard; If condition is not sliced, this is the
- * nonSlicedCondition.
- * [event]: the log event, just in case the metric needs its data, e.g., EventMetric.
- */
- virtual void onMatchedLogEventInternalLocked(
- const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) = 0;
-
- // Consume the parsed stats log entry that already matched the "what" of the metric.
- virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
-
mutable std::mutex mMutex;
- struct Activation {
- Activation(const ActivationType& activationType, const int64_t ttlNs)
- : ttl_ns(ttlNs),
- start_ns(0),
- state(ActivationState::kNotActive),
- activationType(activationType) {}
-
- const int64_t ttl_ns;
- int64_t start_ns;
- ActivationState state;
- const ActivationType activationType;
- };
// When the metric producer has multiple activations, these activations are ORed to determine
// whether the metric producer is ready to generate metrics.
std::unordered_map<int, std::shared_ptr<Activation>> mEventActivationMap;
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 8efca1e10de5..3dad61465416 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -260,17 +260,6 @@ private:
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition);
-
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition);
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 0e33a0f9f29b..7fe5a834f412 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -51,7 +51,6 @@ const int FIELD_ID_VALUE_METRICS = 7;
const int FIELD_ID_TIME_BASE = 9;
const int FIELD_ID_BUCKET_SIZE = 10;
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
-const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
const int FIELD_ID_IS_ACTIVE = 14;
// for ValueMetricDataWrapper
const int FIELD_ID_DATA = 1;
@@ -82,8 +81,11 @@ ValueMetricProducer::ValueMetricProducer(
const ConfigKey& key, const ValueMetric& metric, const int conditionIndex,
const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex,
const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int64_t timeBaseNs,
- const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, conditionWizard),
+ const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager,
+ const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, conditionWizard,
+ eventActivationMap, eventDeactivationMap),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
@@ -109,7 +111,7 @@ ValueMetricProducer::ValueMetricProducer(
mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
: StatsdStats::kPullMaxDelayNs),
mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()),
- // Condition timer will be set in prepareFirstBucketLocked.
+ // Condition timer will be set later within the constructor after pulling events
mConditionTimer(false, timeBaseNs) {
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
@@ -127,10 +129,6 @@ ValueMetricProducer::ValueMetricProducer(
mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
}
- if (metric.has_dimensions_in_condition()) {
- translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
- }
-
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
Metric2Condition mc;
@@ -139,11 +137,10 @@ ValueMetricProducer::ValueMetricProducer(
translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
mMetric2ConditionLinks.push_back(mc);
}
+ mConditionSliced = true;
}
- mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
- mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
- HasPositionALL(metric.dimensions_in_condition());
+ mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
int64_t numBucketsForward = calcBucketsForwardCount(startTimeNs);
mCurrentBucketNum += numBucketsForward;
@@ -160,6 +157,15 @@ ValueMetricProducer::ValueMetricProducer(
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
mConditionTimer.newBucketStart(mCurrentBucketStartTimeNs);
+
+ // Kicks off the puller immediately if condition is true and diff based.
+ if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
+ pullAndMatchEventsLocked(mCurrentBucketStartTimeNs, mCondition);
+ }
+ // Now that activations are processed, start the condition timer if needed.
+ mConditionTimer.onConditionChanged(mIsActive && mCondition == ConditionState::kTrue,
+ mCurrentBucketStartTimeNs);
+
VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mTimeBaseNs);
}
@@ -171,16 +177,6 @@ ValueMetricProducer::~ValueMetricProducer() {
}
}
-void ValueMetricProducer::prepareFirstBucketLocked() {
- // Kicks off the puller immediately if condition is true and diff based.
- if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
- pullAndMatchEventsLocked(mCurrentBucketStartTimeNs, mCondition);
- }
- // Now that activations are processed, start the condition timer if needed.
- mConditionTimer.onConditionChanged(mIsActive && mCondition == ConditionState::kTrue,
- mCurrentBucketStartTimeNs);
-}
-
void ValueMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
const int64_t eventTime) {
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
@@ -243,12 +239,6 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
protoOutput->end(dimenPathToken);
}
- if (!mDimensionsInCondition.empty()) {
- uint64_t dimenPathToken =
- protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
- writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
- protoOutput->end(dimenPathToken);
- }
}
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 739f6ef07cc4..d7cd397da2c0 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -54,10 +54,13 @@ class ValueMetricProducer : public virtual MetricProducer, public virtual PullDa
public:
ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric,
const int conditionIndex, const sp<ConditionWizard>& conditionWizard,
- const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard,
+ const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager);
+ const sp<StatsPullerManager>& pullerManager,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~ValueMetricProducer();
@@ -116,8 +119,6 @@ private:
void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) override;
- void prepareFirstBucketLocked() override;
-
void dropDataLocked(const int64_t dropTimeNs) override;
// Calculate previous bucket end time based on current time.
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 081e61ed21fa..6b5c2994a0c8 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -60,7 +60,7 @@ class DurationTracker {
public:
DurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex,
- const std::vector<Matcher>& dimensionInCondition, bool nesting,
+ bool nesting,
int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs,
int64_t bucketSizeNs, bool conditionSliced, bool fullLink,
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
@@ -70,7 +70,6 @@ public:
mWizard(wizard),
mConditionTrackerIndex(conditionIndex),
mBucketSizeNs(bucketSizeNs),
- mDimensionInCondition(dimensionInCondition),
mNested(nesting),
mCurrentBucketStartTimeNs(currentBucketStartNs),
mDuration(0),
@@ -180,8 +179,6 @@ protected:
const int64_t mBucketSizeNs;
- const std::vector<Matcher>& mDimensionInCondition;
-
const bool mNested;
int64_t mCurrentBucketStartTimeNs;
@@ -196,7 +193,6 @@ protected:
const bool mConditionSliced;
- bool mSameConditionDimensionsInTracker;
bool mHasLinksToAllConditionDimensionsInTracker;
std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 6868b8c24c71..df66cb0c53e5 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -27,18 +27,14 @@ namespace statsd {
MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id,
const MetricDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex,
- const vector<Matcher>& dimensionInCondition, bool nesting,
+ bool nesting,
int64_t currentBucketStartNs, int64_t currentBucketNum,
int64_t startTimeNs, int64_t bucketSizeNs,
bool conditionSliced, bool fullLink,
const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
- : DurationTracker(key, id, eventKey, wizard, conditionIndex, dimensionInCondition, nesting,
+ : DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting,
currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs,
conditionSliced, fullLink, anomalyTrackers) {
- if (mWizard != nullptr) {
- mSameConditionDimensionsInTracker =
- mWizard->equalOutputDimensions(conditionIndex, mDimensionInCondition);
- }
}
unique_ptr<DurationTracker> MaxDurationTracker::clone(const int64_t eventTime) {
@@ -252,17 +248,11 @@ void MaxDurationTracker::onSlicedConditionMayChange(bool overallCondition,
if (pair.second.state == kStopped) {
continue;
}
- std::unordered_set<HashableDimensionKey> conditionDimensionKeySet;
ConditionState conditionState = mWizard->query(
- mConditionTrackerIndex, pair.second.conditionKeys, mDimensionInCondition,
- !mSameConditionDimensionsInTracker,
- !mHasLinksToAllConditionDimensionsInTracker,
- &conditionDimensionKeySet);
- bool conditionMet =
- (conditionState == ConditionState::kTrue) &&
- (mDimensionInCondition.size() == 0 ||
- conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) !=
- conditionDimensionKeySet.end());
+ mConditionTrackerIndex, pair.second.conditionKeys,
+ !mHasLinksToAllConditionDimensionsInTracker);
+ bool conditionMet = (conditionState == ConditionState::kTrue);
+
VLOG("key: %s, condition: %d", pair.first.toString().c_str(), conditionMet);
noteConditionChanged(pair.first, conditionMet, timestamp);
}
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index 8e8f2cd6c582..d0371da096ea 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -30,7 +30,7 @@ class MaxDurationTracker : public DurationTracker {
public:
MaxDurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex,
- const std::vector<Matcher>& dimensionInCondition, bool nesting,
+ bool nesting,
int64_t currentBucketStartNs, int64_t currentBucketNum,
int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced,
bool fullLink,
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index 956383a99eea..b0fd975b2328 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -26,20 +26,16 @@ using std::pair;
OringDurationTracker::OringDurationTracker(
const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
- sp<ConditionWizard> wizard, int conditionIndex, const vector<Matcher>& dimensionInCondition,
+ sp<ConditionWizard> wizard, int conditionIndex,
bool nesting, int64_t currentBucketStartNs, int64_t currentBucketNum,
int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced, bool fullLink,
const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
- : DurationTracker(key, id, eventKey, wizard, conditionIndex, dimensionInCondition, nesting,
+ : DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting,
currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs,
conditionSliced, fullLink, anomalyTrackers),
mStarted(),
mPaused() {
mLastStartTime = 0;
- if (mWizard != nullptr) {
- mSameConditionDimensionsInTracker =
- mWizard->equalOutputDimensions(conditionIndex, mDimensionInCondition);
- }
}
unique_ptr<DurationTracker> OringDurationTracker::clone(const int64_t eventTime) {
@@ -227,17 +223,10 @@ void OringDurationTracker::onSlicedConditionMayChange(bool overallCondition,
++it;
continue;
}
- std::unordered_set<HashableDimensionKey> conditionDimensionKeySet;
ConditionState conditionState =
mWizard->query(mConditionTrackerIndex, condIt->second,
- mDimensionInCondition,
- !mSameConditionDimensionsInTracker,
- !mHasLinksToAllConditionDimensionsInTracker,
- &conditionDimensionKeySet);
- if (conditionState != ConditionState::kTrue ||
- (mDimensionInCondition.size() != 0 &&
- conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) ==
- conditionDimensionKeySet.end())) {
+ !mHasLinksToAllConditionDimensionsInTracker);
+ if (conditionState != ConditionState::kTrue) {
startedToPaused.push_back(*it);
it = mStarted.erase(it);
VLOG("Key %s started -> paused", key.toString().c_str());
@@ -262,17 +251,10 @@ void OringDurationTracker::onSlicedConditionMayChange(bool overallCondition,
++it;
continue;
}
- std::unordered_set<HashableDimensionKey> conditionDimensionKeySet;
ConditionState conditionState =
mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key],
- mDimensionInCondition,
- !mSameConditionDimensionsInTracker,
- !mHasLinksToAllConditionDimensionsInTracker,
- &conditionDimensionKeySet);
- if (conditionState == ConditionState::kTrue &&
- (mDimensionInCondition.size() == 0 ||
- conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) !=
- conditionDimensionKeySet.end())) {
+ !mHasLinksToAllConditionDimensionsInTracker);
+ if (conditionState == ConditionState::kTrue) {
pausedToStarted.push_back(*it);
it = mPaused.erase(it);
VLOG("Key %s paused -> started", key.toString().c_str());
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 8e73256d4a01..43c48d5f536b 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -29,7 +29,7 @@ class OringDurationTracker : public DurationTracker {
public:
OringDurationTracker(const ConfigKey& key, const int64_t& id,
const MetricDimensionKey& eventKey, sp<ConditionWizard> wizard,
- int conditionIndex, const std::vector<Matcher>& dimensionInCondition,
+ int conditionIndex,
bool nesting, int64_t currentBucketStartNs, int64_t currentBucketNum,
int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced,
bool fullLink,
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 5cfb1239d30e..0fee71e1fe2c 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -18,10 +18,11 @@
#include "Log.h"
#include "metrics_manager_util.h"
+#include "MetricProducer.h"
#include "../condition/CombinationConditionTracker.h"
#include "../condition/SimpleConditionTracker.h"
-#include "../condition/StateTracker.h"
+#include "../condition/StateConditionTracker.h"
#include "../external/StatsPullerManager.h"
#include "../matchers/CombinationLogMatchingTracker.h"
#include "../matchers/SimpleLogMatchingTracker.h"
@@ -137,6 +138,62 @@ bool handleMetricWithConditions(
return true;
}
+// Validates a metricActivation and populates state.
+// EventActivationMap and EventDeactivationMap are supplied to a MetricProducer
+// to provide the producer with state about its activators and deactivators.
+// Returns false if there are errors.
+bool handleMetricActivation(
+ const StatsdConfig& config,
+ const int64_t metricId,
+ const int metricIndex,
+ const unordered_map<int64_t, int>& metricToActivationMap,
+ const unordered_map<int64_t, int>& logTrackerMap,
+ unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
+ unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
+ vector<int>& metricsWithActivation,
+ unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap) {
+ // Check if metric has an associated activation
+ auto itr = metricToActivationMap.find(metricId);
+ if (itr == metricToActivationMap.end()) return true;
+
+ int activationIndex = itr->second;
+ const MetricActivation& metricActivation = config.metric_activation(activationIndex);
+
+ for (int i = 0; i < metricActivation.event_activation_size(); i++) {
+ const EventActivation& activation = metricActivation.event_activation(i);
+
+ auto itr = logTrackerMap.find(activation.atom_matcher_id());
+ if (itr == logTrackerMap.end()) {
+ ALOGE("Atom matcher not found for event activation.");
+ return false;
+ }
+
+ ActivationType activationType = (activation.has_activation_type()) ?
+ activation.activation_type() : metricActivation.activation_type();
+ std::shared_ptr<Activation> activationWrapper = std::make_shared<Activation>(
+ activationType, activation.ttl_seconds() * NS_PER_SEC);
+
+ int atomMatcherIndex = itr->second;
+ activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(metricIndex);
+ eventActivationMap.emplace(atomMatcherIndex, activationWrapper);
+
+ if (activation.has_deactivation_atom_matcher_id()) {
+ itr = logTrackerMap.find(activation.deactivation_atom_matcher_id());
+ if (itr == logTrackerMap.end()) {
+ ALOGE("Atom matcher not found for event deactivation.");
+ return false;
+ }
+ int deactivationAtomMatcherIndex = itr->second;
+ deactivationAtomTrackerToMetricMap[deactivationAtomMatcherIndex].push_back(metricIndex);
+ eventDeactivationMap[deactivationAtomMatcherIndex].push_back(activationWrapper);
+ }
+ }
+
+ metricsWithActivation.push_back(metricIndex);
+ return true;
+}
+
bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
unordered_map<int64_t, int>& logTrackerMap,
vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) {
@@ -184,13 +241,13 @@ bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
}
/**
- * A StateTracker is built from a SimplePredicate which has only "start", and no "stop"
+ * A StateConditionTracker is built from a SimplePredicate which has only "start", and no "stop"
* or "stop_all". The start must be an atom matcher that matches a state atom. It must
* have dimension, the dimension must be the state atom's primary fields plus exclusive state
- * field. For example, the StateTracker is used in tracking UidProcessState and ScreenState.
+ * field. For example, the StateConditionTracker is used in tracking UidProcessState and ScreenState.
*
*/
-bool isStateTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) {
+bool isStateConditionTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) {
// 1. must not have "stop". must have "dimension"
if (!simplePredicate.has_stop() && simplePredicate.has_dimensions()) {
auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(
@@ -242,8 +299,8 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
switch (condition.contents_case()) {
case Predicate::ContentsCase::kSimplePredicate: {
vector<Matcher> primaryKeys;
- if (isStateTracker(condition.simple_predicate(), &primaryKeys)) {
- allConditionTrackers.push_back(new StateTracker(key, condition.id(), index,
+ if (isStateConditionTracker(condition.simple_predicate(), &primaryKeys)) {
+ allConditionTrackers.push_back(new StateConditionTracker(key, condition.id(), index,
condition.simple_predicate(),
logTrackerMap, primaryKeys));
} else {
@@ -293,16 +350,33 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
const vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
- unordered_map<int, std::vector<int>>& conditionToMetricMap,
- unordered_map<int, std::vector<int>>& trackerToMetricMap,
- unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds) {
+ unordered_map<int, vector<int>>& conditionToMetricMap,
+ unordered_map<int, vector<int>>& trackerToMetricMap,
+ unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds,
+ unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
+ unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
+ vector<int>& metricsWithActivation) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchers);
const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
- config.event_metric_size() + config.value_metric_size();
+ config.event_metric_size() + config.gauge_metric_size() +
+ config.value_metric_size();
allMetricProducers.reserve(allMetricsCount);
StatsPullerManager statsPullerManager;
+ // Construct map from metric id to metric activation index. The map will be used to determine
+ // the metric activation corresponding to a metric.
+ unordered_map<int64_t, int> metricToActivationMap;
+ for (int i = 0; i < config.metric_activation_size(); i++) {
+ const MetricActivation& metricActivation = config.metric_activation(i);
+ int64_t metricId = metricActivation.metric_id();
+ if (metricToActivationMap.find(metricId) != metricToActivationMap.end()) {
+ ALOGE("Metric %lld has multiple MetricActivations", (long long) metricId);
+ return false;
+ }
+ metricToActivationMap.insert({metricId, i});
+ }
+
// Build MetricProducers for each metric defined in config.
// build CountMetricProducer
for (int i = 0; i < config.count_metric_size(); i++) {
@@ -337,8 +411,17 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
- sp<MetricProducer> countProducer =
- new CountMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs, currentTimeNs);
+ unordered_map<int, shared_ptr<Activation>> eventActivationMap;
+ unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ bool success = handleMetricActivation(config, metric.id(), metricIndex,
+ metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
+ eventDeactivationMap);
+ if (!success) return false;
+
+ sp<MetricProducer> countProducer = new CountMetricProducer(
+ key, metric, conditionIndex, wizard, timeBaseTimeNs, currentTimeNs,
+ eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(countProducer);
}
@@ -406,9 +489,18 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
+ unordered_map<int, shared_ptr<Activation>> eventActivationMap;
+ unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ bool success = handleMetricActivation(config, metric.id(), metricIndex,
+ metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
+ eventDeactivationMap);
+ if (!success) return false;
+
sp<MetricProducer> durationMetric = new DurationMetricProducer(
key, metric, conditionIndex, trackerIndices[0], trackerIndices[1],
- trackerIndices[2], nesting, wizard, internalDimensions, timeBaseTimeNs, currentTimeNs);
+ trackerIndices[2], nesting, wizard, internalDimensions, timeBaseTimeNs,
+ currentTimeNs, eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(durationMetric);
}
@@ -443,8 +535,17 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
- sp<MetricProducer> eventMetric =
- new EventMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs);
+ unordered_map<int, shared_ptr<Activation>> eventActivationMap;
+ unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ bool success = handleMetricActivation(config, metric.id(), metricIndex,
+ metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
+ eventDeactivationMap);
+ if (!success) return false;
+
+ sp<MetricProducer> eventMetric = new EventMetricProducer(
+ key, metric, conditionIndex, wizard, timeBaseTimeNs, eventActivationMap,
+ eventDeactivationMap);
allMetricProducers.push_back(eventMetric);
}
@@ -500,9 +601,18 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
+ unordered_map<int, shared_ptr<Activation>> eventActivationMap;
+ unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ bool success = handleMetricActivation(config, metric.id(), metricIndex,
+ metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
+ eventDeactivationMap);
+ if (!success) return false;
+
sp<MetricProducer> valueProducer = new ValueMetricProducer(
key, metric, conditionIndex, wizard, trackerIndex, matcherWizard, pullTagId,
- timeBaseTimeNs, currentTimeNs, pullerManager);
+ timeBaseTimeNs, currentTimeNs, pullerManager, eventActivationMap,
+ eventDeactivationMap);
allMetricProducers.push_back(valueProducer);
}
@@ -586,10 +696,19 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
+ unordered_map<int, shared_ptr<Activation>> eventActivationMap;
+ unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
+ bool success = handleMetricActivation(config, metric.id(), metricIndex,
+ metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
+ eventDeactivationMap);
+ if (!success) return false;
+
sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
key, metric, conditionIndex, wizard,
trackerIndex, matcherWizard, pullTagId, triggerAtomId, atomTagId,
- timeBaseTimeNs, currentTimeNs, pullerManager);
+ timeBaseTimeNs, currentTimeNs, pullerManager,
+ eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(gaugeProducer);
}
for (int i = 0; i < config.no_report_metric_size(); ++i) {
@@ -707,73 +826,6 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
return true;
}
-bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config,
- const int64_t currentTimeNs,
- const unordered_map<int64_t, int> &logEventTrackerMap,
- const unordered_map<int64_t, int> &metricProducerMap,
- vector<sp<MetricProducer>>& allMetricProducers,
- unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
- unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation) {
- for (int i = 0; i < config.metric_activation_size(); ++i) {
- const MetricActivation& metric_activation = config.metric_activation(i);
- auto itr = metricProducerMap.find(metric_activation.metric_id());
- if (itr == metricProducerMap.end()) {
- ALOGE("Metric id not found in metric activation: %lld",
- (long long)metric_activation.metric_id());
- return false;
- }
- const int metricTrackerIndex = itr->second;
- if (metricTrackerIndex < 0 || metricTrackerIndex >= (int)allMetricProducers.size()) {
- ALOGE("Invalid metric tracker index.");
- return false;
- }
- const sp<MetricProducer>& metric = allMetricProducers[metricTrackerIndex];
- metricsWithActivation.push_back(metricTrackerIndex);
- for (int j = 0; j < metric_activation.event_activation_size(); ++j) {
- const EventActivation& activation = metric_activation.event_activation(j);
- auto logTrackerIt = logEventTrackerMap.find(activation.atom_matcher_id());
- if (logTrackerIt == logEventTrackerMap.end()) {
- ALOGE("Atom matcher not found for event activation.");
- return false;
- }
- const int atomMatcherIndex = logTrackerIt->second;
- activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(
- metricTrackerIndex);
-
- ActivationType activationType;
- if (activation.has_activation_type()) {
- activationType = activation.activation_type();
- } else {
- activationType = metric_activation.activation_type();
- }
-
- if (activation.has_deactivation_atom_matcher_id()) {
- auto deactivationAtomMatcherIt =
- logEventTrackerMap.find(activation.deactivation_atom_matcher_id());
- if (deactivationAtomMatcherIt == logEventTrackerMap.end()) {
- ALOGE("Atom matcher not found for event deactivation.");
- return false;
- }
- const int deactivationMatcherIndex = deactivationAtomMatcherIt->second;
- deactivationAtomTrackerToMetricMap[deactivationMatcherIndex]
- .push_back(metricTrackerIndex);
- metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds(),
- deactivationMatcherIndex);
- } else {
- metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds());
- }
- }
- }
- return true;
-}
-
-void prepareFirstBucket(const vector<sp<MetricProducer>>& allMetricProducers) {
- for (const auto& metric: allMetricProducers) {
- metric->prepareFirstBucket();
- }
-}
-
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
@@ -810,7 +862,8 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
if (!initMetrics(key, config, timeBaseNs, currentTimeNs, uidMap, pullerManager, logTrackerMap,
conditionTrackerMap, allAtomMatchers, allConditionTrackers, allMetricProducers,
conditionToMetricMap, trackerToMetricMap, metricProducerMap,
- noReportMetricIds)) {
+ noReportMetricIds, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
ALOGE("initMetricProducers failed");
return false;
}
@@ -824,14 +877,6 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
ALOGE("initAlarms failed");
return false;
}
- if (!initMetricActivations(key, config, currentTimeNs, logTrackerMap, metricProducerMap,
- allMetricProducers, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
- ALOGE("initMetricActivations failed");
- return false;
- }
-
- prepareFirstBucket(allMetricProducers);
return true;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 028231ff908c..3802948f64da 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -91,7 +91,10 @@ bool initMetrics(
std::vector<sp<MetricProducer>>& allMetricProducers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
- std::set<int64_t>& noReportMetricIds);
+ std::set<int64_t>& noReportMetricIds,
+ std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
+ std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
+ std::vector<int>& metricsWithActivation);
// Initialize MetricsManager from StatsdConfig.
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
@@ -113,7 +116,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
vector<int>& metricsWithActivation,
std::set<int64_t>& noReportMetricIds);
-bool isStateTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys);
+bool isStateConditionTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/state/StateListener.h b/cmds/statsd/src/state/StateListener.h
new file mode 100644
index 000000000000..a31690a102ed
--- /dev/null
+++ b/cmds/statsd/src/state/StateListener.h
@@ -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.
+ */
+#pragma once
+
+#include <utils/RefBase.h>
+
+#include "HashableDimensionKey.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StateListener : public virtual RefBase {
+public:
+ StateListener(){};
+
+ virtual ~StateListener(){};
+
+ /**
+ * Interface for handling a state change.
+ *
+ * The old and new state values map to the original state values.
+ * StateTrackers only track the original state values and are unaware
+ * of higher-level state groups. MetricProducers hold information on
+ * state groups and are responsible for mapping original state values to
+ * the correct state group.
+ *
+ * [atomId]: The id of the state atom
+ * [primaryKey]: The primary field values of the state atom
+ * [oldState]: Previous state value before state change
+ * [newState]: Current state value after state change
+ */
+ virtual void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState,
+ int newState) = 0;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/state/StateManager.cpp b/cmds/statsd/src/state/StateManager.cpp
new file mode 100644
index 000000000000..a3059c5b52ac
--- /dev/null
+++ b/cmds/statsd/src/state/StateManager.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
+
+#include "StateManager.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+StateManager& StateManager::getInstance() {
+ static StateManager sStateManager;
+ return sStateManager;
+}
+
+void StateManager::onLogEvent(const LogEvent& event) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mStateTrackers.find(event.GetTagId()) != mStateTrackers.end()) {
+ mStateTrackers[event.GetTagId()]->onLogEvent(event);
+ }
+}
+
+bool StateManager::registerListener(int stateAtomId, wp<StateListener> listener) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ // Check if state tracker already exists
+ if (mStateTrackers.find(stateAtomId) == mStateTrackers.end()) {
+ // Create a new state tracker iff atom is a state atom
+ auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(stateAtomId);
+ if (it != android::util::AtomsInfo::kStateAtomsFieldOptions.end()) {
+ mStateTrackers[stateAtomId] = new StateTracker(stateAtomId, it->second);
+ } else {
+ ALOGE("StateManager cannot register listener, Atom %d is not a state atom",
+ stateAtomId);
+ return false;
+ }
+ }
+ mStateTrackers[stateAtomId]->registerListener(listener);
+ return true;
+}
+
+void StateManager::unregisterListener(int stateAtomId, wp<StateListener> listener) {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ // Hold the sp<> until the lock is released so that ~StateTracker() is
+ // not called while the lock is held.
+ sp<StateTracker> toRemove;
+
+ // Unregister listener from correct StateTracker
+ auto it = mStateTrackers.find(stateAtomId);
+ if (it != mStateTrackers.end()) {
+ it->second->unregisterListener(listener);
+
+ // Remove the StateTracker if it has no listeners
+ if (it->second->getListenersCount() == 0) {
+ toRemove = it->second;
+ mStateTrackers.erase(it);
+ }
+ } else {
+ ALOGE("StateManager cannot unregister listener, StateTracker for atom %d does not exist",
+ stateAtomId);
+ }
+ lock.unlock();
+}
+
+int StateManager::getState(int stateAtomId, const HashableDimensionKey& key) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mStateTrackers.find(stateAtomId) != mStateTrackers.end()) {
+ return mStateTrackers[stateAtomId]->getState(key);
+ }
+
+ return StateTracker::kStateUnknown;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h
new file mode 100644
index 000000000000..ce60f1482be7
--- /dev/null
+++ b/cmds/statsd/src/state/StateManager.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+#pragma once
+
+//#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include "HashableDimensionKey.h"
+
+#include "state/StateListener.h"
+#include "state/StateTracker.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StateManager : public virtual RefBase {
+public:
+ StateManager(){};
+
+ ~StateManager(){};
+
+ // Returns a pointer to the single, shared StateManager object.
+ static StateManager& getInstance();
+
+ // Notifies the correct StateTracker of an event.
+ void onLogEvent(const LogEvent& event);
+
+ // Returns true if stateAtomId is the id of a state atom and notifies the
+ // correct StateTracker to register the listener. If the correct
+ // StateTracker does not exist, a new StateTracker is created.
+ bool registerListener(int stateAtomId, wp<StateListener> listener);
+
+ // Notifies the correct StateTracker to unregister a listener
+ // and removes the tracker if it no longer has any listeners.
+ void unregisterListener(int stateAtomId, wp<StateListener> listener);
+
+ // Queries the correct StateTracker for the state that is mapped to the given
+ // query key.
+ // If the StateTracker doesn't exist, returns StateTracker::kStateUnknown.
+ int getState(int stateAtomId, const HashableDimensionKey& queryKey);
+
+ inline int getStateTrackersCount() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mStateTrackers.size();
+ }
+
+ inline int getListenersCount(int stateAtomId) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mStateTrackers.find(stateAtomId) != mStateTrackers.end()) {
+ return mStateTrackers[stateAtomId]->getListenersCount();
+ }
+ return -1;
+ }
+
+private:
+ mutable std::mutex mMutex;
+
+ // Maps state atom ids to StateTrackers
+ std::unordered_map<int, sp<StateTracker>> mStateTrackers;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
new file mode 100644
index 000000000000..5a91950b9f8b
--- /dev/null
+++ b/cmds/statsd/src/state/StateTracker.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include "stats_util.h"
+
+#include "StateTracker.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+StateTracker::StateTracker(const int atomId,
+ const util::StateAtomFieldOptions& stateAtomInfo)
+ : mAtomId(atomId),
+ mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) {
+ // create matcher for each primary field
+ // TODO(tsaichristine): handle when primary field is first uid in chain
+ for (const auto& primary : stateAtomInfo.primaryFields) {
+ Matcher matcher = getSimpleMatcher(atomId, primary);
+ mPrimaryFields.push_back(matcher);
+ }
+
+ // TODO(tsaichristine): set default state, reset state, and nesting
+}
+
+void StateTracker::onLogEvent(const LogEvent& event) {
+ // parse event for primary field values i.e. primary key
+ HashableDimensionKey primaryKey;
+ if (mPrimaryFields.size() > 0) {
+ if (!filterValues(mPrimaryFields, event.getValues(), &primaryKey) ||
+ primaryKey.getValues().size() != mPrimaryFields.size()) {
+ ALOGE("StateTracker error extracting primary key from log event.");
+ handleReset();
+ return;
+ }
+ } else {
+ // atom has no primary fields
+ primaryKey = DEFAULT_DIMENSION_KEY;
+ }
+
+ // parse event for state value
+ Value state;
+ int32_t stateValue;
+ if (!filterValues(mStateField, event.getValues(), &state) || state.getType() != INT) {
+ ALOGE("StateTracker error extracting state from log event. Type: %d", state.getType());
+ handlePartialReset(primaryKey);
+ return;
+ }
+ stateValue = state.int_value;
+
+ if (stateValue == mResetState) {
+ VLOG("StateTracker Reset state: %s", state.toString().c_str());
+ handleReset();
+ }
+
+ // track and update state
+ int32_t oldState = 0;
+ int32_t newState = 0;
+ updateState(primaryKey, stateValue, &oldState, &newState);
+
+ // notify all listeners if state has changed
+ if (oldState != newState) {
+ VLOG("StateTracker updated state");
+ for (auto listener : mListeners) {
+ auto sListener = listener.promote(); // safe access to wp<>
+ if (sListener != nullptr) {
+ sListener->onStateChanged(mAtomId, primaryKey, oldState, newState);
+ }
+ }
+ } else {
+ VLOG("StateTracker NO updated state");
+ }
+}
+
+void StateTracker::registerListener(wp<StateListener> listener) {
+ mListeners.insert(listener);
+}
+
+void StateTracker::unregisterListener(wp<StateListener> listener) {
+ mListeners.erase(listener);
+}
+
+int StateTracker::getState(const HashableDimensionKey& queryKey) const {
+ if (queryKey.getValues().size() == mPrimaryFields.size()) {
+ auto it = mStateMap.find(queryKey);
+ if (it != mStateMap.end()) {
+ return it->second.state;
+ }
+ } else if (queryKey.getValues().size() > mPrimaryFields.size()) {
+ ALOGE("StateTracker query key size > primary key size is illegal");
+ } else {
+ ALOGE("StateTracker query key size < primary key size is not supported");
+ }
+ return mDefaultState;
+}
+
+void StateTracker::handleReset() {
+ VLOG("StateTracker handle reset");
+ for (const auto pair : mStateMap) {
+ for (auto l : mListeners) {
+ auto sl = l.promote();
+ if (sl != nullptr) {
+ sl->onStateChanged(mAtomId, pair.first, pair.second.state, mDefaultState);
+ }
+ }
+ }
+ mStateMap.clear();
+}
+
+void StateTracker::handlePartialReset(const HashableDimensionKey& primaryKey) {
+ VLOG("StateTracker handle partial reset");
+ if (mStateMap.find(primaryKey) != mStateMap.end()) {
+ mStateMap.erase(primaryKey);
+ }
+}
+
+void StateTracker::updateState(const HashableDimensionKey& primaryKey, const int32_t eventState,
+ int32_t* oldState, int32_t* newState) {
+ // get old state (either current state in map or default state)
+ auto it = mStateMap.find(primaryKey);
+ if (it != mStateMap.end()) {
+ *oldState = it->second.state;
+ } else {
+ *oldState = mDefaultState;
+ }
+
+ // update state map
+ if (eventState == mDefaultState) {
+ // remove (key, state) pair if state returns to default state
+ VLOG("\t StateTracker changed to default state")
+ mStateMap.erase(primaryKey);
+ } else {
+ mStateMap[primaryKey].state = eventState;
+ mStateMap[primaryKey].count = 1;
+ }
+ *newState = eventState;
+
+ // TODO(tsaichristine): support atoms with nested counting
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
new file mode 100644
index 000000000000..f22706c8418d
--- /dev/null
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <statslog.h>
+#include <utils/RefBase.h>
+#include "HashableDimensionKey.h"
+#include "logd/LogEvent.h"
+
+#include "state/StateListener.h"
+
+#include <unordered_map>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StateTracker : public virtual RefBase {
+public:
+ StateTracker(const int atomId, const util::StateAtomFieldOptions& stateAtomInfo);
+
+ virtual ~StateTracker(){};
+
+ // Updates state map and notifies all listeners if a state change occurs.
+ // Checks if a state change has occurred by getting the state value from
+ // the log event and comparing the old and new states.
+ void onLogEvent(const LogEvent& event);
+
+ // Adds new listeners to set of StateListeners. If a listener is already
+ // registered, it is ignored.
+ void registerListener(wp<StateListener> listener);
+
+ void unregisterListener(wp<StateListener> listener);
+
+ // Returns the state value mapped to the given query key.
+ // If the key isn't mapped to a state or the key size doesn't match the
+ // primary key size, the default state is returned.
+ int getState(const HashableDimensionKey& queryKey) const;
+
+ inline int getListenersCount() const {
+ return mListeners.size();
+ }
+
+ const static int kStateUnknown = -1;
+
+private:
+ struct StateValueInfo {
+ int32_t state; // state value
+ int count; // nested count (only used for binary states)
+ };
+
+ const int32_t mAtomId; // id of the state atom being tracked
+
+ Matcher mStateField; // matches the atom's exclusive state field
+
+ std::vector<Matcher> mPrimaryFields; // matches the atom's primary fields
+
+ int32_t mDefaultState = kStateUnknown;
+
+ int32_t mResetState;
+
+ // Maps primary key to state value info
+ std::unordered_map<HashableDimensionKey, StateValueInfo> mStateMap;
+
+ // Set of all StateListeners (objects listening for state changes)
+ std::set<wp<StateListener>> mListeners;
+
+ // Reset all state values in map to default state
+ void handleReset();
+
+ // Reset only the state value mapped to primary key to default state
+ void handlePartialReset(const HashableDimensionKey& primaryKey);
+
+ // Update the StateMap based on the received state value.
+ // Store the old and new states.
+ void updateState(const HashableDimensionKey& primaryKey, const int32_t eventState,
+ int32_t* oldState, int32_t* newState);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index b87547056ad3..e45e24fe49d4 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -41,6 +41,15 @@ message DimensionsValueTuple {
repeated DimensionsValue dimensions_value = 1;
}
+message StateValue {
+ optional int32 atom_id = 1;
+
+ oneof contents {
+ int64 group_id = 2;
+ int32 value = 3;
+ }
+}
+
message EventMetricData {
optional int64 elapsed_timestamp_nanos = 1;
@@ -66,13 +75,15 @@ message CountBucketInfo {
message CountMetricData {
optional DimensionsValue dimensions_in_what = 1;
- optional DimensionsValue dimensions_in_condition = 2;
+ repeated StateValue slice_by_state = 6;
repeated CountBucketInfo bucket_info = 3;
repeated DimensionsValue dimension_leaf_values_in_what = 4;
- repeated DimensionsValue dimension_leaf_values_in_condition = 5;
+ optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
+
+ repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true];
}
message DurationBucketInfo {
@@ -92,13 +103,13 @@ message DurationBucketInfo {
message DurationMetricData {
optional DimensionsValue dimensions_in_what = 1;
- optional DimensionsValue dimensions_in_condition = 2;
+ optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
repeated DurationBucketInfo bucket_info = 3;
repeated DimensionsValue dimension_leaf_values_in_what = 4;
- repeated DimensionsValue dimension_leaf_values_in_condition = 5;
+ repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true];
}
message ValueBucketInfo {
@@ -136,13 +147,13 @@ message ValueBucketInfo {
message ValueMetricData {
optional DimensionsValue dimensions_in_what = 1;
- optional DimensionsValue dimensions_in_condition = 2;
+ optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
repeated ValueBucketInfo bucket_info = 3;
repeated DimensionsValue dimension_leaf_values_in_what = 4;
- repeated DimensionsValue dimension_leaf_values_in_condition = 5;
+ repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true];
}
message GaugeBucketInfo {
@@ -166,13 +177,13 @@ message GaugeBucketInfo {
message GaugeMetricData {
optional DimensionsValue dimensions_in_what = 1;
- optional DimensionsValue dimensions_in_condition = 2;
+ optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
repeated GaugeBucketInfo bucket_info = 3;
repeated DimensionsValue dimension_leaf_values_in_what = 4;
- repeated DimensionsValue dimension_leaf_values_in_condition = 5;
+ repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true];
}
message StatsLogReport {
@@ -220,7 +231,7 @@ message StatsLogReport {
optional DimensionsValue dimensions_path_in_what = 11;
- optional DimensionsValue dimensions_path_in_condition = 12;
+ optional DimensionsValue dimensions_path_in_condition = 12 [deprecated = true];
// DO NOT USE field 13.
@@ -363,7 +374,7 @@ message StatsdStatsReport {
repeated ConditionStats condition_stats = 14;
repeated MetricStats metric_stats = 15;
repeated AlertStats alert_stats = 16;
- repeated MetricStats metric_dimension_in_condition_stats = 17;
+ repeated MetricStats metric_dimension_in_condition_stats = 17 [deprecated = true];
message Annotation {
optional int64 field_int64 = 1;
optional int32 field_int32 = 2;
@@ -483,7 +494,7 @@ message AlertTriggerDetails {
message MetricValue {
optional int64 metric_id = 1;
optional DimensionsValue dimension_in_what = 2;
- optional DimensionsValue dimension_in_condition = 3;
+ optional DimensionsValue dimension_in_condition = 3 [deprecated = true];
optional int64 value = 4;
}
oneof value {
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 67625eb82454..c22e3cc07a3b 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -445,6 +445,8 @@ int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
return 12 * 60 * 60 * 1000LL;
case ONE_DAY:
return 24 * 60 * 60 * 1000LL;
+ case ONE_WEEK:
+ return 7 * 24 * 60 * 60 * 1000LL;
case CTS:
return 1000;
case TIME_UNIT_UNSPECIFIED:
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 79c06b98a82d..c98b2cf4b472 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -44,6 +44,7 @@ enum TimeUnit {
SIX_HOURS = 7;
TWELVE_HOURS = 8;
ONE_DAY = 9;
+ ONE_WEEK = 10;
CTS = 1000;
}
@@ -150,6 +151,24 @@ message Predicate {
}
}
+message StateMap {
+ message StateGroup {
+ optional int64 group_id = 1;
+
+ repeated int32 value = 2;
+ }
+
+ repeated StateGroup group = 1;
+}
+
+message State {
+ optional int64 id = 1;
+
+ optional int32 atom_id = 2;
+
+ optional StateMap map = 3;
+}
+
message MetricConditionLink {
optional int64 condition = 1;
@@ -158,6 +177,14 @@ message MetricConditionLink {
optional FieldMatcher fields_in_condition = 3;
}
+message MetricStateLink {
+ optional int64 state = 1;
+
+ optional FieldMatcher fields_in_what = 2;
+
+ optional FieldMatcher fields_in_state = 3;
+}
+
message FieldFilter {
optional bool include_all = 1 [default = false];
optional FieldMatcher fields = 2;
@@ -182,11 +209,15 @@ message CountMetric {
optional FieldMatcher dimensions_in_what = 4;
- optional FieldMatcher dimensions_in_condition = 7;
+ repeated int64 slice_by_state = 8;
optional TimeUnit bucket = 5;
repeated MetricConditionLink links = 6;
+
+ repeated MetricStateLink state_link = 9;
+
+ optional FieldMatcher dimensions_in_condition = 7 [deprecated = true];
}
message DurationMetric {
@@ -207,7 +238,7 @@ message DurationMetric {
optional FieldMatcher dimensions_in_what = 6;
- optional FieldMatcher dimensions_in_condition = 8;
+ optional FieldMatcher dimensions_in_condition = 8 [deprecated = true];
optional TimeUnit bucket = 7;
}
@@ -225,7 +256,7 @@ message GaugeMetric {
optional FieldMatcher dimensions_in_what = 5;
- optional FieldMatcher dimensions_in_condition = 8;
+ optional FieldMatcher dimensions_in_condition = 8 [deprecated = true];
optional TimeUnit bucket = 6;
@@ -259,7 +290,7 @@ message ValueMetric {
optional FieldMatcher dimensions_in_what = 5;
- optional FieldMatcher dimensions_in_condition = 9;
+ optional FieldMatcher dimensions_in_condition = 9 [deprecated = true];
optional TimeUnit bucket = 6;
@@ -438,6 +469,8 @@ message StatsdConfig {
optional bool persist_locally = 20 [default = false];
+ repeated State state = 21;
+
// Field number 1000 is reserved for later use.
reserved 1000;
}
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 2b9528f7d1de..441d3c896467 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -29,6 +29,7 @@ using std::unordered_map;
using std::vector;
const int32_t TAG_ID = 123;
+const int32_t TAG_ID_2 = 28; // hardcoded tag of atom with uid field
const int FIELD_ID_1 = 1;
const int FIELD_ID_2 = 2;
const int FIELD_ID_3 = 2;
@@ -297,6 +298,46 @@ TEST(AtomMatcherTest, TestAttributionMatcher) {
EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
}
+TEST(AtomMatcherTest, TestUidFieldMatcher) {
+ UidMap uidMap;
+ uidMap.updateMap(
+ 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+ {android::String16("v1"), android::String16("v1"), android::String16("v2"),
+ android::String16("v1"), android::String16("v2")},
+ {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
+ android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
+ {android::String16(""), android::String16(""), android::String16(""),
+ android::String16(""), android::String16("")});
+
+ // Set up matcher
+ AtomMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+ simpleMatcher->set_atom_id(TAG_ID);
+ simpleMatcher->add_field_value_matcher()->set_field(1);
+ simpleMatcher->mutable_field_value_matcher(0)->set_eq_string("pkg0");
+
+ // Set up the event
+ LogEvent event(TAG_ID, 0);
+ event.write(1111);
+ event.init();
+
+ LogEvent event2(TAG_ID_2, 0);
+ event2.write(1111);
+ event2.write("some value");
+ event2.init();
+
+ // Tag not in kAtomsWithUidField
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+ // Tag found in kAtomsWithUidField and has matching uid
+ simpleMatcher->set_atom_id(TAG_ID_2);
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+
+ // Tag found in kAtomsWithUidField but has non-matching uid
+ simpleMatcher->mutable_field_value_matcher(0)->set_eq_string("Pkg2");
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2));
+}
+
TEST(AtomMatcherTest, TestNeqAnyStringMatcher) {
UidMap uidMap;
uidMap.updateMap(
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 504ee22f72e4..0743480bf4ee 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -582,7 +582,7 @@ TEST(LogEventTest, TestBinaryFieldAtom) {
event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS);
event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW);
event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS);
- event1.write(extension_str);
+ event1.writeBytes(extension_str);
event1.init();
ProtoOutputStream proto;
@@ -621,7 +621,7 @@ TEST(LogEventTest, TestBinaryFieldAtom_empty) {
event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS);
event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW);
event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS);
- event1.write(extension_str);
+ event1.writeBytes(extension_str);
event1.init();
ProtoOutputStream proto;
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index fe25a257aa67..460b9e0995c8 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -1199,87 +1199,66 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
ConfigKey cfgKey1(uid, 12341);
long timeBase1 = 1;
- sp<StatsLogProcessor> processor =
+ sp<StatsLogProcessor> processor1 =
CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
// Metric 1 is not active.
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_EQ(1, processor->mMetricsManagers.size());
- auto it = processor->mMetricsManagers.find(cfgKey1);
- EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ EXPECT_EQ(1, processor1->mMetricsManagers.size());
+ auto it = processor1->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor1->mMetricsManagers.end());
auto& metricsManager1 = it->second;
EXPECT_TRUE(metricsManager1->isActive());
- auto metricIt = metricsManager1->mAllMetricProducers.begin();
- for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId1) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
- auto& metricProducer1 = *metricIt;
- EXPECT_FALSE(metricProducer1->isActive());
-
- metricIt = metricsManager1->mAllMetricProducers.begin();
- for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId2) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
- auto& metricProducer2 = *metricIt;
- EXPECT_TRUE(metricProducer2->isActive());
-
- int i = 0;
- for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
- if (metricsManager1->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger1->atom_matcher_id()) {
- break;
- }
- }
- const auto& activation1 = metricProducer1->mEventActivationMap.at(i);
- EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
- EXPECT_EQ(0, activation1->start_ns);
- EXPECT_EQ(kNotActive, activation1->state);
- EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType);
-
- i = 0;
- for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
- if (metricsManager1->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger2->atom_matcher_id()) {
- break;
- }
- }
- const auto& activation2 = metricProducer1->mEventActivationMap.at(i);
- EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
- EXPECT_EQ(0, activation2->start_ns);
- EXPECT_EQ(kNotActive, activation2->state);
- EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType);
+ EXPECT_EQ(metricsManager1->mAllMetricProducers.size(), 2);
+ // We assume that the index of a MetricProducer within the mAllMetricProducers
+ // array follows the order in which metrics are added to the config.
+ auto& metricProducer1_1 = metricsManager1->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer1_1->getMetricId(), metricId1);
+ EXPECT_FALSE(metricProducer1_1->isActive()); // inactive due to associated MetricActivation
+
+ auto& metricProducer1_2 = metricsManager1->mAllMetricProducers[1];
+ EXPECT_EQ(metricProducer1_2->getMetricId(), metricId2);
+ EXPECT_TRUE(metricProducer1_2->isActive());
+
+ EXPECT_EQ(metricProducer1_1->mEventActivationMap.size(), 2);
+ // The key in mEventActivationMap is the index of the associated atom matcher. We assume
+ // that matchers are indexed in the order that they are added to the config.
+ const auto& activation1_1_1 = metricProducer1_1->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1_1_1->ttl_ns);
+ EXPECT_EQ(0, activation1_1_1->start_ns);
+ EXPECT_EQ(kNotActive, activation1_1_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation1_1_1->activationType);
+
+ const auto& activation1_1_2 = metricProducer1_1->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation1_1_2->ttl_ns);
+ EXPECT_EQ(0, activation1_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1_1_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1_1_2->activationType);
// }}}------------------------------------------------------------------------------
// Trigger Activation 1 for Metric 1
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
- processor->OnLogEvent(event.get());
+ processor1->OnLogEvent(event.get());
// Metric 1 is not active; Activation 1 set to kActiveOnBoot
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_FALSE(metricProducer1->isActive());
- EXPECT_EQ(0, activation1->start_ns);
- EXPECT_EQ(kActiveOnBoot, activation1->state);
- EXPECT_EQ(0, activation2->start_ns);
- EXPECT_EQ(kNotActive, activation2->state);
+ EXPECT_FALSE(metricProducer1_1->isActive());
+ EXPECT_EQ(0, activation1_1_1->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1_1_1->state);
+ EXPECT_EQ(0, activation1_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1_1_2->state);
- EXPECT_TRUE(metricProducer2->isActive());
+ EXPECT_TRUE(metricProducer1_2->isActive());
// }}}-----------------------------------------------------------------------------
// Simulate shutdown by saving state to disk
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
- processor->SaveActiveConfigsToDisk(shutDownTime);
- EXPECT_FALSE(metricProducer1->isActive());
- int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
+ processor1->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_FALSE(metricProducer1_1->isActive());
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
// same config.
@@ -1293,55 +1272,34 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
EXPECT_EQ(1, processor2->mMetricsManagers.size());
it = processor2->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
- auto& metricsManager1001 = it->second;
- EXPECT_TRUE(metricsManager1001->isActive());
-
- metricIt = metricsManager1001->mAllMetricProducers.begin();
- for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId1) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
- auto& metricProducer1001 = *metricIt;
- EXPECT_FALSE(metricProducer1001->isActive());
-
- metricIt = metricsManager1001->mAllMetricProducers.begin();
- for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId2) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
- auto& metricProducer1002 = *metricIt;
- EXPECT_TRUE(metricProducer1002->isActive());
-
- i = 0;
- for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
- if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger1->atom_matcher_id()) {
- break;
- }
- }
- const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i);
- EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns);
- EXPECT_EQ(0, activation1001_1->start_ns);
- EXPECT_EQ(kNotActive, activation1001_1->state);
- EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001_1->activationType);
-
- i = 0;
- for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
- if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger2->atom_matcher_id()) {
- break;
- }
- }
+ auto& metricsManager2 = it->second;
+ EXPECT_TRUE(metricsManager2->isActive());
- const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i);
- EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns);
- EXPECT_EQ(0, activation1001_2->start_ns);
- EXPECT_EQ(kNotActive, activation1001_2->state);
- EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1001_2->activationType);
+ EXPECT_EQ(metricsManager2->mAllMetricProducers.size(), 2);
+ // We assume that the index of a MetricProducer within the mAllMetricProducers
+ // array follows the order in which metrics are added to the config.
+ auto& metricProducer2_1 = metricsManager2->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer2_1->getMetricId(), metricId1);
+ EXPECT_FALSE(metricProducer2_1->isActive());
+
+ auto& metricProducer2_2 = metricsManager2->mAllMetricProducers[1];
+ EXPECT_EQ(metricProducer2_2->getMetricId(), metricId2);
+ EXPECT_TRUE(metricProducer2_2->isActive());
+
+ EXPECT_EQ(metricProducer2_1->mEventActivationMap.size(), 2);
+ // The key in mEventActivationMap is the index of the associated atom matcher. We assume
+ // that matchers are indexed in the order that they are added to the config.
+ const auto& activation2_1_1 = metricProducer2_1->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation2_1_1->ttl_ns);
+ EXPECT_EQ(0, activation2_1_1->start_ns);
+ EXPECT_EQ(kNotActive, activation2_1_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation2_1_1->activationType);
+
+ const auto& activation2_1_2 = metricProducer2_1->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation2_1_2->ttl_ns);
+ EXPECT_EQ(0, activation2_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation2_1_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2_1_2->activationType);
// }}}-----------------------------------------------------------------------------------
// Load saved state from disk.
@@ -1350,13 +1308,14 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
// Metric 1 active; Activation 1 is active, Activation 2 is not active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_TRUE(metricProducer1001->isActive());
- EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
- EXPECT_EQ(kActive, activation1001_1->state);
- EXPECT_EQ(0, activation1001_2->start_ns);
- EXPECT_EQ(kNotActive, activation1001_2->state);
+ EXPECT_TRUE(metricProducer2_1->isActive());
+ int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
+ EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
+ EXPECT_EQ(kActive, activation2_1_1->state);
+ EXPECT_EQ(0, activation2_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation2_1_2->state);
- EXPECT_TRUE(metricProducer1002->isActive());
+ EXPECT_TRUE(metricProducer2_2->isActive());
// }}}--------------------------------------------------------------------------------
// Trigger Activation 2 for Metric 1.
@@ -1369,23 +1328,23 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
// Metric 1 active; Activation 1 is active, Activation 2 is active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_TRUE(metricProducer1001->isActive());
- EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
- EXPECT_EQ(kActive, activation1001_1->state);
- EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation1001_2->start_ns);
- EXPECT_EQ(kActive, activation1001_2->state);
+ EXPECT_TRUE(metricProducer2_1->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
+ EXPECT_EQ(kActive, activation2_1_1->state);
+ EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation2_1_2->start_ns);
+ EXPECT_EQ(kActive, activation2_1_2->state);
- EXPECT_TRUE(metricProducer1002->isActive());
+ EXPECT_TRUE(metricProducer2_2->isActive());
// }}}---------------------------------------------------------------------------
// Simulate shutdown by saving state to disk
shutDownTime = timeBase2 + 50 * NS_PER_SEC;
processor2->SaveActiveConfigsToDisk(shutDownTime);
- EXPECT_TRUE(metricProducer1001->isActive());
- EXPECT_TRUE(metricProducer1002->isActive());
- ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime;
- int64_t ttl2 = screenOnEvent->GetElapsedTimestampNs() +
- metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime;
+ EXPECT_TRUE(metricProducer2_1->isActive());
+ EXPECT_TRUE(metricProducer2_2->isActive());
+ ttl1 -= shutDownTime - timeBase2;
+ int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC
+ - (shutDownTime - screenOnEvent->GetElapsedTimestampNs());
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
// same config.
@@ -1399,55 +1358,34 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
EXPECT_EQ(1, processor3->mMetricsManagers.size());
it = processor3->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor3->mMetricsManagers.end());
- auto& metricsManagerTimeBase3 = it->second;
- EXPECT_TRUE(metricsManagerTimeBase3->isActive());
-
- metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
- for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId1) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
- auto& metricProducerTimeBase3_1 = *metricIt;
- EXPECT_FALSE(metricProducerTimeBase3_1->isActive());
-
- metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
- for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
- if ((*metricIt)->getMetricId() == metricId2) {
- break;
- }
- }
- EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
- auto& metricProducerTimeBase3_2 = *metricIt;
- EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
-
- i = 0;
- for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
- if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger1->atom_matcher_id()) {
- break;
- }
- }
- const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
- EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns);
- EXPECT_EQ(0, activationTimeBase3_1->start_ns);
- EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
- EXPECT_EQ(ACTIVATE_ON_BOOT, activationTimeBase3_1->activationType);
-
- i = 0;
- for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
- if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
- metric1ActivationTrigger2->atom_matcher_id()) {
- break;
- }
- }
+ auto& metricsManager3 = it->second;
+ EXPECT_TRUE(metricsManager3->isActive());
- const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
- EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns);
- EXPECT_EQ(0, activationTimeBase3_2->start_ns);
- EXPECT_EQ(kNotActive, activationTimeBase3_2->state);
- EXPECT_EQ(ACTIVATE_IMMEDIATELY, activationTimeBase3_2->activationType);
+ EXPECT_EQ(metricsManager3->mAllMetricProducers.size(), 2);
+ // We assume that the index of a MetricProducer within the mAllMetricProducers
+ // array follows the order in which metrics are added to the config.
+ auto& metricProducer3_1 = metricsManager3->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer3_1->getMetricId(), metricId1);
+ EXPECT_FALSE(metricProducer3_1->isActive());
+
+ auto& metricProducer3_2 = metricsManager3->mAllMetricProducers[1];
+ EXPECT_EQ(metricProducer3_2->getMetricId(), metricId2);
+ EXPECT_TRUE(metricProducer3_2->isActive());
+
+ EXPECT_EQ(metricProducer3_1->mEventActivationMap.size(), 2);
+ // The key in mEventActivationMap is the index of the associated atom matcher. We assume
+ // that matchers are indexed in the order that they are added to the config.
+ const auto& activation3_1_1 = metricProducer3_1->mEventActivationMap.at(0);
+ EXPECT_EQ(100 * NS_PER_SEC, activation3_1_1->ttl_ns);
+ EXPECT_EQ(0, activation3_1_1->start_ns);
+ EXPECT_EQ(kNotActive, activation3_1_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation3_1_1->activationType);
+
+ const auto& activation3_1_2 = metricProducer3_1->mEventActivationMap.at(1);
+ EXPECT_EQ(200 * NS_PER_SEC, activation3_1_2->ttl_ns);
+ EXPECT_EQ(0, activation3_1_2->start_ns);
+ EXPECT_EQ(kNotActive, activation3_1_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation3_1_2->activationType);
// }}}----------------------------------------------------------------------------------
// Load saved state from disk.
@@ -1456,13 +1394,13 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
// Metric 1 active: Activation 1 is active, Activation 2 is active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
- EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns);
- EXPECT_EQ(kActive, activationTimeBase3_1->state);
- EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
- EXPECT_EQ(kActive, activationTimeBase3_2->state);
+ EXPECT_TRUE(metricProducer3_1->isActive());
+ EXPECT_EQ(timeBase3 + ttl1 - activation3_1_1->ttl_ns, activation3_1_1->start_ns);
+ EXPECT_EQ(kActive, activation3_1_1->state);
+ EXPECT_EQ(timeBase3 + ttl2 - activation3_1_2->ttl_ns, activation3_1_2->start_ns);
+ EXPECT_EQ(kActive, activation3_1_2->state);
- EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ EXPECT_TRUE(metricProducer3_2->isActive());
// }}}-------------------------------------------------------------------------------
@@ -1473,15 +1411,16 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi
);
processor3->OnLogEvent(screenOnEvent.get());
- // Metric 1 active; Activation 1 is not active, Activation 2 is set to active
+ // Metric 1 active; Activation 1 is inactive (above screenOnEvent causes ttl1 to expire),
+ // Activation 2 is set to active
// Metric 2 is active.
// {{{---------------------------------------------------------------------------
- EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
- EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
- EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activationTimeBase3_2->start_ns);
- EXPECT_EQ(kActive, activationTimeBase3_2->state);
+ EXPECT_TRUE(metricProducer3_1->isActive());
+ EXPECT_EQ(kNotActive, activation3_1_1->state);
+ EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation3_1_2->start_ns);
+ EXPECT_EQ(kActive, activation3_1_2->state);
- EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ EXPECT_TRUE(metricProducer3_2->isActive());
// }}}---------------------------------------------------------------------------
}
@@ -1713,6 +1652,11 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) {
EXPECT_EQ(kActive, activation1004->state);
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1004->activationType);
// }}}------------------------------------------------------------------------------
+
+ // Clear the data stored on disk as a result of the system server death.
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey1, configAddedTimeNs + NS_PER_SEC, false, true,
+ ADB_DUMP, FAST, &buffer);
}
#else
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index e826a52c2f33..6eaa2311e5ed 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -268,8 +268,6 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
std::vector<sp<ConditionTracker>> allConditions;
for (Position position :
{ Position::FIRST, Position::LAST}) {
- vector<Matcher> dimensionInCondition;
- std::unordered_set<HashableDimensionKey> dimensionKeys;
SimplePredicate simplePredicate = getWakeLockHeldCondition(
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
@@ -321,9 +319,9 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
const auto queryKey = getWakeLockQueryKey(position, uids, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
- false, false,
- conditionCache, dimensionKeys);
+ conditionTracker.isConditionMet(queryKey, allPredicates,
+ false,
+ conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by this uid
@@ -389,9 +387,9 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
// query again
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
- false, false,
- conditionCache, dimensionKeys);
+ conditionTracker.isConditionMet(queryKey, allPredicates,
+ false,
+ conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
@@ -399,8 +397,6 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
std::vector<sp<ConditionTracker>> allConditions;
- vector<Matcher> dimensionInCondition;
- std::unordered_set<HashableDimensionKey> dimensionKeys;
SimplePredicate simplePredicate = getWakeLockHeldCondition(
true /*nesting*/, true /*default to false*/, false /*slice output by uid*/,
@@ -445,9 +441,9 @@ TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
ConditionKey queryKey;
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
- true, true,
- conditionCache, dimensionKeys);
+ conditionTracker.isConditionMet(queryKey, allPredicates,
+ true,
+ conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by this uid
@@ -489,10 +485,9 @@ TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
// query again
conditionCache[0] = ConditionState::kNotEvaluated;
- dimensionKeys.clear();
- conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
- true, true,
- conditionCache, dimensionKeys);
+ conditionTracker.isConditionMet(queryKey, allPredicates,
+ true,
+ conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
@@ -500,8 +495,6 @@ TEST(SimpleConditionTrackerTest, TestStopAll) {
std::vector<sp<ConditionTracker>> allConditions;
for (Position position :
{ Position::FIRST, Position::LAST }) {
- vector<Matcher> dimensionInCondition;
- std::unordered_set<HashableDimensionKey> dimensionKeys;
SimplePredicate simplePredicate = getWakeLockHeldCondition(
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
position);
@@ -555,9 +548,9 @@ TEST(SimpleConditionTrackerTest, TestStopAll) {
const auto queryKey = getWakeLockQueryKey(position, uid_list1, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
- false, false,
- conditionCache, dimensionKeys);
+ conditionTracker.isConditionMet(queryKey, allPredicates,
+ false,
+ conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by uid2
@@ -594,9 +587,9 @@ TEST(SimpleConditionTrackerTest, TestStopAll) {
// TEST QUERY
const auto queryKey2 = getWakeLockQueryKey(position, uid_list2, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
- false, false,
- conditionCache, dimensionKeys);
+ conditionTracker.isConditionMet(queryKey, allPredicates,
+ false,
+ conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -628,17 +621,17 @@ TEST(SimpleConditionTrackerTest, TestStopAll) {
// TEST QUERY
const auto queryKey3 = getWakeLockQueryKey(position, uid_list1, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
- false, false,
- conditionCache, dimensionKeys);
+ conditionTracker.isConditionMet(queryKey, allPredicates,
+ false,
+ conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
// TEST QUERY
const auto queryKey4 = getWakeLockQueryKey(position, uid_list2, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
- false, false,
- conditionCache, dimensionKeys);
+ conditionTracker.isConditionMet(queryKey, allPredicates,
+ false,
+ conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
}
diff --git a/cmds/statsd/tests/condition/StateTracker_test.cpp b/cmds/statsd/tests/condition/StateConditionTracker_test.cpp
index 9a66254afce0..fbf6efdcf966 100644
--- a/cmds/statsd/tests/condition/StateTracker_test.cpp
+++ b/cmds/statsd/tests/condition/StateConditionTracker_test.cpp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "src/condition/StateTracker.h"
+#include "src/condition/StateConditionTracker.h"
#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
@@ -50,7 +50,7 @@ void makeUidProcStateEvent(int32_t uid, int32_t state, LogEvent* event) {
event->init();
}
-TEST(StateTrackerTest, TestStateChange) {
+TEST(StateConditionTrackerTest, TestStateChange) {
int uid1 = 111;
int uid2 = 222;
@@ -60,7 +60,7 @@ TEST(StateTrackerTest, TestStateChange) {
trackerNameIndexMap[StringToId("UidProcState")] = 0;
vector<Matcher> primaryFields;
primaryFields.push_back(getSimpleMatcher(kUidProcTag, 1));
- StateTracker tracker(ConfigKey(12, 123), 123, 0, getUidProcStatePredicate(),
+ StateConditionTracker tracker(ConfigKey(12, 123), 123, 0, getUidProcStatePredicate(),
trackerNameIndexMap, primaryFields);
LogEvent event(kUidProcTag, 0 /*timestamp*/);
diff --git a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
index b98dc60086ac..325e869e5a9b 100644
--- a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
@@ -96,6 +96,11 @@ TEST(ConfigTtlE2eTest, TestCountMetric) {
EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC),
processor->mMetricsManagers.begin()->second->getTtlEndNs());
+
+ // Clear the data stored on disk as a result of the ttl.
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true,
+ ADB_DUMP, FAST, &buffer);
}
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
deleted file mode 100644
index e4186b7200a0..000000000000
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
+++ /dev/null
@@ -1,961 +0,0 @@
-// Copyright (C) 2017 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 <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
- DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition,
- bool hashStringInReport) {
- StatsdConfig config;
- config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
- *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-
- auto scheduledJobPredicate = CreateScheduledJobPredicate();
- auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
- dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
- dimensions->add_child()->set_field(2); // job name field.
-
- auto screenIsOffPredicate = CreateScreenIsOffPredicate();
-
- auto isSyncingPredicate = CreateIsSyncingPredicate();
- auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
- {Position::FIRST});
- if (addExtraDimensionInCondition) {
- syncDimension->add_child()->set_field(2 /* name field*/);
- }
-
- config.set_hash_strings_in_metric_report(hashStringInReport);
- *config.add_predicate() = scheduledJobPredicate;
- *config.add_predicate() = screenIsOffPredicate;
- *config.add_predicate() = isSyncingPredicate;
- auto combinationPredicate = config.add_predicate();
- combinationPredicate->set_id(StringToId("CombinationPredicate"));
- combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
- addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
- addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
-
- auto metric = config.add_duration_metric();
- metric->set_bucket(FIVE_MINUTES);
- metric->set_id(StringToId("scheduledJob"));
- metric->set_what(scheduledJobPredicate.id());
- metric->set_condition(combinationPredicate->id());
- metric->set_aggregation_type(aggregationType);
- auto dimensionWhat = metric->mutable_dimensions_in_what();
- dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
- dimensionWhat->add_child()->set_field(2); // job name field.
- *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- return config;
-}
-
-} // namespace
-
-/*
- The following test has the following input.
-
-{ 10000000002 10000000002 (8)9999[I], [S], job0[S], 1[I], }
-{ 10000000010 10000000010 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 1[I], }
-{ 10000000011 10000000011 (29)1[I], }
-{ 10000000040 10000000040 (29)2[I], }
-{ 10000000050 10000000050 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 0[I], }
-{ 10000000101 10000000101 (8)9999[I], [S], job0[S], 0[I], }
-{ 10000000102 10000000102 (29)1[I], }
-{ 10000000200 10000000200 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 1[I], }
-{ 10000000201 10000000201 (8)9999[I], [S], job2[S], 1[I], }
-{ 10000000400 10000000400 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadDoc[S], 1[I], }
-{ 10000000401 10000000401 (7)333[I], App2[S], 222[I], GMSCoreModule1[S], 555[I], GMSCoreModule2[S], ReadEmail[S], 1[I], }
-{ 10000000450 10000000450 (29)2[I], }
-{ 10000000500 10000000500 (8)9999[I], [S], job2[S], 0[I], }
-{ 10000000600 10000000600 (8)8888[I], [S], job2[S], 1[I], }
-{ 10000000650 10000000650 (29)1[I], }
-{ 309999999999 309999999999 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadDoc[S], 0[I], }
-{ 310000000100 310000000100 (29)2[I], }
-{ 310000000300 310000000300 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 0[I], }
-{ 310000000600 310000000600 (8)8888[I], [S], job1[S], 1[I], }
-{ 310000000640 310000000640 (29)1[I], }
-{ 310000000650 310000000650 (29)2[I], }
-{ 310000000700 310000000700 (7)333[I], App2[S], 222[I], GMSCoreModule1[S], 555[I], GMSCoreModule2[S], ReadEmail[S], 0[I], }
-{ 310000000850 310000000850 (8)8888[I], [S], job2[S], 0[I], }
-{ 310000000900 310000000900 (8)8888[I], [S], job1[S], 0[I], }
-*/
-TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition) {
- for (const bool hashStringInReport : { true, false }) {
- for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : { true, false }) {
- for (auto aggregationType : {DurationMetric::MAX_SPARSE, DurationMetric::SUM}) {
- ConfigKey cfgKey;
- auto config = CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
- aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension,
- hashStringInReport);
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(
- config.duration_metric(0).bucket()) * 1000000LL;
-
- auto processor = CreateStatsLogProcessor(
- bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
- std::vector<AttributionNodeInternal> attributions1 = {
- CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {
- CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<std::unique_ptr<LogEvent>> events;
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 11));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 40));
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 102));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 450));
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 650));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + bucketSizeNs + 100));
-
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + bucketSizeNs + 640));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + bucketSizeNs + 650));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job2",
- bucketStartTimeNs + bucketSizeNs + 850));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job1",
- bucketStartTimeNs + bucketSizeNs + 600));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job1",
- bucketStartTimeNs + bucketSizeNs + 900));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 10));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 50));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 200));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 300));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
- bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + 401));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- backfillDimensionPath(&reports);
- backfillStringInReport(&reports);
- backfillStartEndTimestamp(&reports);
-
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::DurationMetricDataWrapper metrics;
- sortMetricDataByDimensionsValue(
- reports.reports(0).metrics(0).duration_metrics(), &metrics);
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(metrics.data_size(), 4);
- auto data = metrics.data(0);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().
- dimensions_value(0).value_str(),
- "job0"); // job name
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
-
- data = metrics.data(1);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().
- dimensions_value(0).value_str(),
- "job1"); // job name
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(2);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().
- dimensions_value(0).value_str(),
- "job2"); // job name
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201 + bucketSizeNs - 650);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(3);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().
- dimensions_value(0).value_str(),
- "job2"); // job name
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401 + bucketSizeNs - 650);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100 + 650 - 640);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- } else {
- EXPECT_EQ(metrics.data_size(), 4);
- auto data = metrics.data(0);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().
- dimensions_value(0).value_str(),
- "job0"); // job name
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().
- dimensions_value(0).value_str(),
- "job1"); // job name
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(2);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
- "job2"); // job name
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 650 + 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(3);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().
- dimensions_value(0).value_str(),
- "job2"); // job name
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 650 + 110);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- }
- }
- }
- }
-}
-
-namespace {
-
-StatsdConfig CreateDurationMetricConfig_Link_AND_CombinationCondition(
- DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
- StatsdConfig config;
- config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
- *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-
- auto scheduledJobPredicate = CreateScheduledJobPredicate();
- auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
- *dimensions = CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
- dimensions->add_child()->set_field(2); // job name field.
-
- auto isSyncingPredicate = CreateIsSyncingPredicate();
- auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- if (addExtraDimensionInCondition) {
- syncDimension->add_child()->set_field(2 /* name field*/);
- }
-
- auto screenIsOffPredicate = CreateScreenIsOffPredicate();
-
- *config.add_predicate() = scheduledJobPredicate;
- *config.add_predicate() = screenIsOffPredicate;
- *config.add_predicate() = isSyncingPredicate;
- auto combinationPredicate = config.add_predicate();
- combinationPredicate->set_id(StringToId("CombinationPredicate"));
- combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
- addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
- addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
-
- auto metric = config.add_duration_metric();
- metric->set_bucket(FIVE_MINUTES);
- metric->set_id(StringToId("scheduledJob"));
- metric->set_what(scheduledJobPredicate.id());
- metric->set_condition(combinationPredicate->id());
- metric->set_aggregation_type(aggregationType);
- *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
-
- auto links = metric->add_links();
- links->set_condition(isSyncingPredicate.id());
- *links->mutable_fields_in_what() =
- CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
- *links->mutable_fields_in_condition() =
- CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- return config;
-}
-
-} // namespace
-
-TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition) {
- for (bool isFullLink : {true, false}) {
- for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
- ConfigKey cfgKey;
- auto config = CreateDurationMetricConfig_Link_AND_CombinationCondition(
- aggregationType, !isFullLink);
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
- auto processor = CreateStatsLogProcessor(
- bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
- std::vector<AttributionNodeInternal> attributions1 = {
- CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {
- CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions3 = {
- CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<std::unique_ptr<LogEvent>> events;
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 55));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 120));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 121));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 450));
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 501));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + bucketSizeNs + 100));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2",
- bucketStartTimeNs + bucketSizeNs + 850));
-
- events.push_back(
- CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
- bucketStartTimeNs + bucketSizeNs - 2));
- events.push_back(
- CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
- bucketStartTimeNs + bucketSizeNs + 900));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 50));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 110));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + 300));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
- events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
- bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + 550));
- events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + 800));
- events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
- events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs + 700));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- backfillDimensionPath(&reports);
- backfillStringInReport(&reports);
- backfillStartEndTimestamp(&reports);
-
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::DurationMetricDataWrapper metrics;
- sortMetricDataByDimensionsValue(
- reports.reports(0).metrics(0).duration_metrics(), &metrics);
-
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(metrics.data_size(), 3);
- auto data = metrics.data(0);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(2);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- } else {
- EXPECT_EQ(metrics.data_size(), 3);
- auto data = metrics.data(0);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(2);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- }
- }
- }
-}
-
-namespace {
-
-StatsdConfig CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(
- DurationMetric::AggregationType aggregationType, bool hashStringInReport) {
- StatsdConfig config;
- config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
- *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-
- auto scheduledJobPredicate = CreateScheduledJobPredicate();
- auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
- *dimensions = CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
- dimensions->add_child()->set_field(2); // job name field.
-
- auto isSyncingPredicate = CreateIsSyncingPredicate();
- auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- syncDimension->add_child()->set_field(2 /* name field*/);
-
- auto screenIsOffPredicate = CreateScreenIsOffPredicate();
-
- config.set_hash_strings_in_metric_report(hashStringInReport);
- *config.add_predicate() = scheduledJobPredicate;
- *config.add_predicate() = screenIsOffPredicate;
- *config.add_predicate() = isSyncingPredicate;
- auto combinationPredicate = config.add_predicate();
- combinationPredicate->set_id(StringToId("CombinationPredicate"));
- combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
- addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
- addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
-
- auto metric = config.add_duration_metric();
- metric->set_bucket(FIVE_MINUTES);
- metric->set_id(StringToId("scheduledJob"));
- metric->set_what(scheduledJobPredicate.id());
- metric->set_condition(combinationPredicate->id());
- metric->set_aggregation_type(aggregationType);
- *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
- *metric->mutable_dimensions_in_condition() = *syncDimension;
-
-
- auto links = metric->add_links();
- links->set_condition(isSyncingPredicate.id());
- *links->mutable_fields_in_what() =
- CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
- *links->mutable_fields_in_condition() =
- CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- return config;
-}
-
-} // namespace
-
-TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition) {
- for (const bool hashStringInReport : {true, false}) {
- for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
- ConfigKey cfgKey;
- auto config =
- CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(
- aggregationType, hashStringInReport);
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
- auto processor = CreateStatsLogProcessor(
- bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
- std::vector<AttributionNodeInternal> attributions1 = {
- CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {
- CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions3 = {
- CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<std::unique_ptr<LogEvent>> events;
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 55));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 120));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 121));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 450));
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 501));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + bucketSizeNs + 100));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2",
- bucketStartTimeNs + bucketSizeNs + 850));
-
- events.push_back(
- CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
- bucketStartTimeNs + bucketSizeNs - 2));
- events.push_back(
- CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
- bucketStartTimeNs + bucketSizeNs + 900));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 50));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 110));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + 300));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
- events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
- bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + 550));
- events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + 800));
- events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
- events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs + 700));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- backfillDimensionPath(&reports);
- backfillStringInReport(&reports);
- backfillStartEndTimestamp(&reports);
-
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::DurationMetricDataWrapper metrics;
- sortMetricDataByDimensionsValue(
- reports.reports(0).metrics(0).duration_metrics(), &metrics);
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(metrics.data_size(), 4);
- auto data = metrics.data(0);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
- EXPECT_EQ("ReadEmail",
- data.dimensions_in_condition().value_tuple().
- dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
- EXPECT_EQ("ReadDoc",
- data.dimensions_in_condition().value_tuple().
- dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 600 + 50);
-
- data = metrics.data(2);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
- EXPECT_EQ("ReadEmail",
- data.dimensions_in_condition().value_tuple().
- dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(3);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
- EXPECT_EQ("ReadDoc",
- data.dimensions_in_condition().value_tuple().
- dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- } else {
- EXPECT_EQ(metrics.data_size(), 4);
- auto data = metrics.data(0);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
- EXPECT_EQ("ReadEmail",
- data.dimensions_in_condition().value_tuple().
- dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
- EXPECT_EQ("ReadDoc",
- data.dimensions_in_condition().value_tuple().
- dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 50);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(2);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
- EXPECT_EQ("ReadEmail",
- data.dimensions_in_condition().value_tuple().
- dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(3);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
- EXPECT_EQ("ReadDoc",
- data.dimensions_in_condition().value_tuple().
- dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- }
- }
- }
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
deleted file mode 100644
index f3ecd56dd946..000000000000
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
+++ /dev/null
@@ -1,816 +0,0 @@
-// Copyright (C) 2017 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 <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateCountMetric_NoLink_CombinationCondition_Config() {
- StatsdConfig config;
- config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- auto screenBrightnessChangeAtomMatcher = CreateScreenBrightnessChangedAtomMatcher();
- *config.add_atom_matcher() = screenBrightnessChangeAtomMatcher;
- *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
- *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
- *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-
- auto screenIsOffPredicate = CreateScreenIsOffPredicate();
- *config.add_predicate() = screenIsOffPredicate;
-
- auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
- // The predicate is dimensioning by any attribution node and both by uid and tag.
- *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
- CreateAttributionUidAndTagDimensions(android::util::WAKELOCK_STATE_CHANGED,
- {Position::FIRST});
- *config.add_predicate() = holdingWakelockPredicate;
-
- auto combinationPredicate = config.add_predicate();
- combinationPredicate->set_id(987654);
- combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
- addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
- addPredicateToPredicateCombination(holdingWakelockPredicate, combinationPredicate);
-
- auto metric = config.add_count_metric();
- metric->set_id(StringToId("ScreenBrightnessChangeMetric"));
- metric->set_what(screenBrightnessChangeAtomMatcher.id());
- metric->set_condition(combinationPredicate->id());
- *metric->mutable_dimensions_in_what() =
- CreateDimensions(android::util::SCREEN_BRIGHTNESS_CHANGED, {1 /* level */});
- *metric->mutable_dimensions_in_condition() = CreateAttributionUidDimensions(
- android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
- metric->set_bucket(FIVE_MINUTES);
- return config;
-}
-
-} // namespace
-
-TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition) {
- ConfigKey cfgKey;
- auto config = CreateCountMetric_NoLink_CombinationCondition_Config();
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
- std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
- CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(333, "App2"),
- CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<std::unique_ptr<LogEvent>> events;
- events.push_back(
- CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 100));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + bucketSizeNs + 1));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 2 * bucketSizeNs - 10));
-
- events.push_back(CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 200));
- events.push_back(
- CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1));
-
- events.push_back(CreateAcquireWakelockEvent(attributions2, "wl2",
- bucketStartTimeNs + bucketSizeNs - 100));
- events.push_back(CreateReleaseWakelockEvent(attributions2, "wl2",
- bucketStartTimeNs + 2 * bucketSizeNs - 50));
-
- events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 11));
- events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 101));
- events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 201));
- events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + 203));
- events.push_back(
- CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs - 99));
- events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs - 2));
- events.push_back(CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + bucketSizeNs - 1));
- events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs + 2));
- events.push_back(
- CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 11));
- events.push_back(
- CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 9));
- events.push_back(
- CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 1));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- backfillDimensionPath(&reports);
- backfillStringInReport(&reports);
- backfillStartEndTimestamp(&reports);
-
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::CountMetricDataWrapper countMetrics;
- sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-
- EXPECT_EQ(countMetrics.data_size(), 7);
- auto data = countMetrics.data(0);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 123);
- EXPECT_FALSE(data.dimensions_in_condition().has_field());
-
- data = countMetrics.data(1);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 123);
- ValidateAttributionUidDimension(data.dimensions_in_condition(),
- android::util::WAKELOCK_STATE_CHANGED, 111);
-
- data = countMetrics.data(2);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).count(), 3);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 456);
- ValidateAttributionUidDimension(data.dimensions_in_condition(),
- android::util::WAKELOCK_STATE_CHANGED, 111);
-
- data = countMetrics.data(3);
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).count(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 456);
- ValidateAttributionUidDimension(data.dimensions_in_condition(),
- android::util::WAKELOCK_STATE_CHANGED, 333);
-
- data = countMetrics.data(4);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
- EXPECT_FALSE(data.dimensions_in_condition().has_field());
-
- data = countMetrics.data(5);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
- ValidateAttributionUidDimension(data.dimensions_in_condition(),
- android::util::WAKELOCK_STATE_CHANGED, 111);
-
- data = countMetrics.data(6);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
- ValidateAttributionUidDimension(data.dimensions_in_condition(),
- android::util::WAKELOCK_STATE_CHANGED, 333);
-}
-
-namespace {
-
-StatsdConfig CreateCountMetric_Link_CombinationCondition() {
- StatsdConfig config;
- config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- auto appCrashMatcher = CreateProcessCrashAtomMatcher();
- *config.add_atom_matcher() = appCrashMatcher;
- *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
- *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
- *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
-
- auto screenIsOffPredicate = CreateScreenIsOffPredicate();
- auto isSyncingPredicate = CreateIsSyncingPredicate();
- auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
- {Position::FIRST});
- syncDimension->add_child()->set_field(2 /* name field*/);
-
- *config.add_predicate() = screenIsOffPredicate;
- *config.add_predicate() = isSyncingPredicate;
- auto combinationPredicate = config.add_predicate();
- combinationPredicate->set_id(987654);
- combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
- addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
- addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
-
- auto metric = config.add_count_metric();
- metric->set_bucket(FIVE_MINUTES);
- metric->set_id(StringToId("AppCrashMetric"));
- metric->set_what(appCrashMatcher.id());
- metric->set_condition(combinationPredicate->id());
- *metric->mutable_dimensions_in_what() =
- CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1 /* uid */});
- *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
-
- // Links between crash atom and condition of app is in syncing.
- auto links = metric->add_links();
- links->set_condition(isSyncingPredicate.id());
- auto dimensionWhat = links->mutable_fields_in_what();
- dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
- dimensionWhat->add_child()->set_field(1); // uid field.
- *links->mutable_fields_in_condition() =
- CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- return config;
-}
-
-} // namespace
-
-TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition) {
- ConfigKey cfgKey;
- auto config = CreateCountMetric_Link_CombinationCondition();
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
- CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(333, "App2"),
- CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<std::unique_ptr<LogEvent>> events;
-
- events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 11));
- events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 101));
- events.push_back(CreateAppCrashEvent(222, bucketStartTimeNs + 101));
-
- events.push_back(CreateAppCrashEvent(222, bucketStartTimeNs + 201));
- events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 211));
- events.push_back(CreateAppCrashEvent(333, bucketStartTimeNs + 211));
-
- events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 401));
- events.push_back(CreateAppCrashEvent(333, bucketStartTimeNs + 401));
- events.push_back(CreateAppCrashEvent(555, bucketStartTimeNs + 401));
-
- events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + bucketSizeNs + 301));
- events.push_back(CreateAppCrashEvent(333, bucketStartTimeNs + bucketSizeNs + 301));
-
- events.push_back(CreateAppCrashEvent(777, bucketStartTimeNs + bucketSizeNs + 701));
-
- events.push_back(
- CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 100));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 202));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + bucketSizeNs + 700));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
- events.push_back(
- CreateSyncEndEvent(attributions1, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
- events.push_back(
- CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 400));
- events.push_back(
- CreateSyncEndEvent(attributions2, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 600));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- backfillDimensionPath(&reports);
- backfillStringInReport(&reports);
- backfillStartEndTimestamp(&reports);
-
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::CountMetricDataWrapper countMetrics;
- sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-
- EXPECT_EQ(countMetrics.data_size(), 5);
- auto data = countMetrics.data(0);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
- EXPECT_FALSE(data.dimensions_in_condition().has_field());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-
- data = countMetrics.data(1);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-
- data = countMetrics.data(2);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 222);
- EXPECT_FALSE(data.dimensions_in_condition().has_field());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-
- data = countMetrics.data(3);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 333);
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).count(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = countMetrics.data(4);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 777);
- EXPECT_FALSE(data.dimensions_in_condition().has_field());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-}
-
-namespace {
-
-StatsdConfig CreateDurationMetricConfig_NoLink_CombinationCondition(
- DurationMetric::AggregationType aggregationType) {
- StatsdConfig config;
- config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- *config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher();
- *config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
- *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
- *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
-
- auto inBatterySaverModePredicate = CreateBatterySaverModePredicate();
-
- auto screenIsOffPredicate = CreateScreenIsOffPredicate();
- auto isSyncingPredicate = CreateIsSyncingPredicate();
- auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
- {Position::FIRST});
- syncDimension->add_child()->set_field(2 /* name field */);
-
- *config.add_predicate() = inBatterySaverModePredicate;
- *config.add_predicate() = screenIsOffPredicate;
- *config.add_predicate() = isSyncingPredicate;
- auto combinationPredicate = config.add_predicate();
- combinationPredicate->set_id(987654);
- combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
- addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
- addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
-
- auto metric = config.add_duration_metric();
- metric->set_bucket(FIVE_MINUTES);
- metric->set_id(StringToId("BatterySaverModeDurationMetric"));
- metric->set_what(inBatterySaverModePredicate.id());
- metric->set_condition(combinationPredicate->id());
- metric->set_aggregation_type(aggregationType);
- *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- return config;
-}
-
-} // namespace
-
-TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition) {
- for (auto aggregationType : { DurationMetric::MAX_SPARSE, DurationMetric::SUM}) {
- ConfigKey cfgKey;
- auto config = CreateDurationMetricConfig_NoLink_CombinationCondition(aggregationType);
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
- auto processor = CreateStatsLogProcessor(
- bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
- std::vector<AttributionNodeInternal> attributions1 = {
- CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {
- CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<std::unique_ptr<LogEvent>> events;
-
- events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 1));
- events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 101));
- events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 110));
-
- events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 201));
- events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 500));
-
- events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 600));
- events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + bucketSizeNs + 850));
-
- events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + bucketSizeNs + 870));
- events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + bucketSizeNs + 900));
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 10));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 100));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 202));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + bucketSizeNs + 800));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 300));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
- events.push_back(
- CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 401));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- backfillDimensionPath(&reports);
- backfillStringInReport(&reports);
- backfillStartEndTimestamp(&reports);
-
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::DurationMetricDataWrapper metrics;
- sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metrics);
-
- EXPECT_EQ(metrics.data_size(), 3);
- auto data = metrics.data(0);
- EXPECT_FALSE(data.dimensions_in_what().has_field());
- EXPECT_FALSE(data.dimensions_in_condition().has_field());
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- } else {
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- }
-
- data = metrics.data(1);
- EXPECT_FALSE(data.dimensions_in_what().has_field());
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 2);
-
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
- } else {
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 300);
- }
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(2);
- EXPECT_FALSE(data.dimensions_in_what().has_field());
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 2);
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- } else {
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs + 700 - 600);
- }
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- }
-}
-
-namespace {
-
-StatsdConfig CreateDurationMetricConfig_Link_CombinationCondition(
- DurationMetric::AggregationType aggregationType) {
- StatsdConfig config;
- config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
- *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
- *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
- *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
- *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
-
- auto screenIsOffPredicate = CreateScreenIsOffPredicate();
- auto isSyncingPredicate = CreateIsSyncingPredicate();
- auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
- {Position::FIRST});
- syncDimension->add_child()->set_field(2 /* name field */);
-
- auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
- *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
- CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */});
-
- *config.add_predicate() = screenIsOffPredicate;
- *config.add_predicate() = isSyncingPredicate;
- *config.add_predicate() = isInBackgroundPredicate;
- auto combinationPredicate = config.add_predicate();
- combinationPredicate->set_id(987654);
- combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
- addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
- addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
-
- auto metric = config.add_duration_metric();
- metric->set_bucket(FIVE_MINUTES);
- metric->set_id(StringToId("AppInBackgroundMetric"));
- metric->set_what(isInBackgroundPredicate.id());
- metric->set_condition(combinationPredicate->id());
- metric->set_aggregation_type(aggregationType);
- *metric->mutable_dimensions_in_what() =
- CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */});
- *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
-
- // Links between crash atom and condition of app is in syncing.
- auto links = metric->add_links();
- links->set_condition(isSyncingPredicate.id());
- auto dimensionWhat = links->mutable_fields_in_what();
- dimensionWhat->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
- dimensionWhat->add_child()->set_field(1); // uid field.
- *links->mutable_fields_in_condition() =
- CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- return config;
-}
-
-} // namespace
-
-TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition) {
- for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
- ConfigKey cfgKey;
- auto config = CreateDurationMetricConfig_Link_CombinationCondition(aggregationType);
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
- auto processor = CreateStatsLogProcessor(
- bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
- std::vector<AttributionNodeInternal> attributions1 = {
- CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {
- CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<std::unique_ptr<LogEvent>> events;
-
- events.push_back(CreateMoveToBackgroundEvent(111, bucketStartTimeNs + 101));
- events.push_back(CreateMoveToForegroundEvent(111, bucketStartTimeNs + 110));
-
- events.push_back(CreateMoveToBackgroundEvent(111, bucketStartTimeNs + 201));
- events.push_back(CreateMoveToForegroundEvent(111, bucketStartTimeNs + bucketSizeNs + 100));
-
- events.push_back(CreateMoveToBackgroundEvent(333, bucketStartTimeNs + 399));
- events.push_back(CreateMoveToForegroundEvent(333, bucketStartTimeNs + bucketSizeNs + 800));
-
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 10));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + 100));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
- bucketStartTimeNs + 202));
- events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
- bucketStartTimeNs + bucketSizeNs + 801));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 300));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
- events.push_back(
- CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 401));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- backfillDimensionPath(&reports);
- backfillStringInReport(&reports);
- backfillStartEndTimestamp(&reports);
-
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::DurationMetricDataWrapper metrics;
- sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metrics);
-
- EXPECT_EQ(metrics.data_size(), 3);
- auto data = metrics.data(0);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
- EXPECT_FALSE(data.dimensions_in_condition().has_field());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 201);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- } else {
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs + 100 - 201);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- }
-
- data = metrics.data(2);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 333);
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 401);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- } else {
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs + 299);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- }
- }
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
deleted file mode 100644
index 489bb0b21a2e..000000000000
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
+++ /dev/null
@@ -1,814 +0,0 @@
-// Copyright (C) 2017 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 <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateDurationMetricConfig_NoLink_SimpleCondition(
- DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
- StatsdConfig config;
- config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
- *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
-
- auto scheduledJobPredicate = CreateScheduledJobPredicate();
- auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
- dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
- dimensions->add_child()->set_field(2); // job name field.
-
- auto isSyncingPredicate = CreateIsSyncingPredicate();
- auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
- {Position::FIRST});
- if (addExtraDimensionInCondition) {
- syncDimension->add_child()->set_field(2 /* name field*/);
- }
-
- *config.add_predicate() = scheduledJobPredicate;
- *config.add_predicate() = isSyncingPredicate;
-
- auto metric = config.add_duration_metric();
- metric->set_bucket(FIVE_MINUTES);
- metric->set_id(StringToId("scheduledJob"));
- metric->set_what(scheduledJobPredicate.id());
- metric->set_condition(isSyncingPredicate.id());
- metric->set_aggregation_type(aggregationType);
- auto dimensionWhat = metric->mutable_dimensions_in_what();
- dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
- dimensionWhat->add_child()->set_field(2); // job name field.
- *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- return config;
-}
-
-} // namespace
-
-TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition) {
- for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : {true, false}) {
- for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
- ConfigKey cfgKey;
- auto config = CreateDurationMetricConfig_NoLink_SimpleCondition(
- aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension);
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
- auto processor = CreateStatsLogProcessor(
- bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
- std::vector<AttributionNodeInternal> attributions1 = {
- CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {
- CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<std::unique_ptr<LogEvent>> events;
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 1));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 10));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 50));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 200));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 300));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
- bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + 401));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- backfillDimensionPath(&reports);
- backfillStringInReport(&reports);
- backfillStartEndTimestamp(&reports);
-
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::DurationMetricDataWrapper metrics;
- sortMetricDataByDimensionsValue(
- reports.reports(0).metrics(0).duration_metrics(), &metrics);
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(metrics.data_size(), 4);
- auto data = metrics.data(0);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
- "job0"); // job name
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
- "job1"); // job name
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(2);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
- "job2"); // job name
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(3);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
- "job2"); // job name
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- } else {
- EXPECT_EQ(metrics.data_size(), 4);
- auto data = metrics.data(0);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
- "job0"); // job name
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
- "job1"); // job name
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(2);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
- "job2"); // job name
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 300);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(3);
- EXPECT_EQ(data.dimensions_in_what().field(),
- android::util::SCHEDULED_JOB_STATE_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
- 2); // job name field
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
- "job2"); // job name
- ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
- android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 );
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- }
- }
- }
-}
-
-namespace {
-
-StatsdConfig createDurationMetric_Link_SimpleConditionConfig(
- DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
- StatsdConfig config;
- config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
- *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
-
- auto scheduledJobPredicate = CreateScheduledJobPredicate();
- auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
- *dimensions = CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
- dimensions->add_child()->set_field(2); // job name field.
-
- auto isSyncingPredicate = CreateIsSyncingPredicate();
- auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- if (addExtraDimensionInCondition) {
- syncDimension->add_child()->set_field(2 /* name field*/);
- }
-
- *config.add_predicate() = scheduledJobPredicate;
- *config.add_predicate() = isSyncingPredicate;
-
- auto metric = config.add_duration_metric();
- metric->set_bucket(FIVE_MINUTES);
- metric->set_id(StringToId("scheduledJob"));
- metric->set_what(scheduledJobPredicate.id());
- metric->set_condition(isSyncingPredicate.id());
- metric->set_aggregation_type(aggregationType);
- *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
-
- auto links = metric->add_links();
- links->set_condition(isSyncingPredicate.id());
- *links->mutable_fields_in_what() =
- CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
- *links->mutable_fields_in_condition() =
- CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- return config;
-}
-
-} // namespace
-
-TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition) {
- for (bool isFullLink : {true, false}) {
- for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
- ConfigKey cfgKey;
- auto config = createDurationMetric_Link_SimpleConditionConfig(
- aggregationType, !isFullLink);
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
- auto processor = CreateStatsLogProcessor(
- bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
- std::vector<AttributionNodeInternal> attributions1 = {
- CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {
- CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions3 = {
- CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<std::unique_ptr<LogEvent>> events;
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
- events.push_back(
- CreateFinishScheduledJobEvent({CreateAttribution(333, "App2")}, "job2",
- bucketStartTimeNs + bucketSizeNs + 850));
-
- events.push_back(
- CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
- bucketStartTimeNs + bucketSizeNs - 2));
- events.push_back(
- CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
- bucketStartTimeNs + bucketSizeNs + 900));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 50));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 110));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + 300));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
- events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
- bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + 550));
- events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + 800));
- events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
- events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs + 700));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- true, ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- backfillDimensionPath(&reports);
- backfillStringInReport(&reports);
- backfillStartEndTimestamp(&reports);
-
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::DurationMetricDataWrapper metrics;
- sortMetricDataByDimensionsValue(
- reports.reports(0).metrics(0).duration_metrics(), &metrics);
-
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(metrics.data_size(), 3);
- auto data = metrics.data(0);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(2);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- } else {
- EXPECT_EQ(metrics.data_size(), 3);
- auto data = metrics.data(0);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(2);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- }
- }
- }
-}
-
-namespace {
-
-StatsdConfig createDurationMetric_PartialLink_SimpleConditionConfig(
- DurationMetric::AggregationType aggregationType) {
- StatsdConfig config;
- config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
- *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
- *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
-
- auto scheduledJobPredicate = CreateScheduledJobPredicate();
- auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
- *dimensions = CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
- dimensions->add_child()->set_field(2); // job name field.
-
- auto isSyncingPredicate = CreateIsSyncingPredicate();
- auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- syncDimension->add_child()->set_field(2 /* name field*/);
-
- *config.add_predicate() = scheduledJobPredicate;
- *config.add_predicate() = isSyncingPredicate;
-
- auto metric = config.add_duration_metric();
- metric->set_bucket(FIVE_MINUTES);
- metric->set_id(StringToId("scheduledJob"));
- metric->set_what(scheduledJobPredicate.id());
- metric->set_condition(isSyncingPredicate.id());
- metric->set_aggregation_type(aggregationType);
- *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
- *metric->mutable_dimensions_in_condition() = *syncDimension;
-
- auto links = metric->add_links();
- links->set_condition(isSyncingPredicate.id());
- *links->mutable_fields_in_what() =
- CreateAttributionUidDimensions(
- android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
- *links->mutable_fields_in_condition() =
- CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
- return config;
-}
-
-} // namespace
-
-TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition) {
- for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
- ConfigKey cfgKey;
- auto config = createDurationMetric_PartialLink_SimpleConditionConfig(
- aggregationType);
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
- auto processor = CreateStatsLogProcessor(
- bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
- std::vector<AttributionNodeInternal> attributions1 = {
- CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions2 = {
- CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<AttributionNodeInternal> attributions3 = {
- CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
-
- std::vector<std::unique_ptr<LogEvent>> events;
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
-
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
- events.push_back(CreateStartScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
- events.push_back(CreateFinishScheduledJobEvent(
- {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + bucketSizeNs + 850));
-
- events.push_back(
- CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
- bucketStartTimeNs + bucketSizeNs - 2));
- events.push_back(
- CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
- bucketStartTimeNs + bucketSizeNs + 900));
-
- events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 50));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + 110));
-
- events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + 300));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
- events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
- bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
-
- events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + 550));
- events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + 800));
- events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
- events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs + 700));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
-
- ConfigMetricsReportList reports;
- vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, FAST, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- backfillDimensionPath(&reports);
- backfillStringInReport(&reports);
- backfillStartEndTimestamp(&reports);
-
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::DurationMetricDataWrapper metrics;
- sortMetricDataByDimensionsValue(
- reports.reports(0).metrics(0).duration_metrics(), &metrics);
-
- if (aggregationType == DurationMetric::SUM) {
- EXPECT_EQ(4, metrics.data_size());
- auto data = metrics.data(0);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
- EXPECT_EQ("ReadEmail",
- data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
- EXPECT_EQ("ReadDoc",
- data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 400 - 100);
-
- data = metrics.data(2);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
- EXPECT_EQ("ReadEmail",
- data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(3);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
- EXPECT_EQ("ReadDoc",
- data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- } else {
- EXPECT_EQ(metrics.data_size(), 4);
- auto data = metrics.data(0);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
- EXPECT_EQ("ReadEmail",
- data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
-
- data = metrics.data(1);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
- EXPECT_EQ("ReadDoc",
- data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
-
- data = metrics.data(2);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
- EXPECT_EQ("ReadEmail",
- data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
-
- data = metrics.data(3);
- ValidateAttributionUidDimension(
- data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
- ValidateAttributionUidDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
- EXPECT_EQ("ReadDoc",
- data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
- bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
- bucketStartTimeNs + 2 * bucketSizeNs);
- }
- }
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
index bdc52b0af34c..e91fb0d4b27c 100644
--- a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
@@ -56,8 +56,9 @@ static const int32_t VULKAN_VERSION = 1;
static const int32_t CPU_VULKAN_VERSION = 2;
static const int32_t GLES_VERSION = 3;
static const bool CPU_VULKAN_IN_USE = true;
+static const bool FALSE_PREROTATION = true;
static const size_t NUMBER_OF_VALUES_GLOBAL = 13;
-static const size_t NUMBER_OF_VALUES_APP = 6;
+static const size_t NUMBER_OF_VALUES_APP = 7;
// clang-format on
class MockGpuStatsPuller : public GpuStatsPuller {
@@ -150,6 +151,7 @@ TEST_F(GpuStatsPuller_test, PullGpuStatsAppInfo) {
EXPECT_TRUE(event->write(int64VectorToProtoByteString(vkDriverLoadingTime)));
EXPECT_TRUE(event->write(int64VectorToProtoByteString(angleDriverLoadingTime)));
EXPECT_TRUE(event->write(CPU_VULKAN_IN_USE));
+ EXPECT_TRUE(event->write(FALSE_PREROTATION));
event->init();
inData.emplace_back(event);
MockGpuStatsPuller mockPuller(android::util::GPU_STATS_APP_INFO, &inData);
@@ -168,6 +170,7 @@ TEST_F(GpuStatsPuller_test, PullGpuStatsAppInfo) {
EXPECT_EQ(int64VectorToProtoByteString(angleDriverLoadingTime),
outData[0]->getValues()[4].mValue.str_value);
EXPECT_EQ(CPU_VULKAN_IN_USE, outData[0]->getValues()[5].mValue.int_value);
+ EXPECT_EQ(FALSE_PREROTATION, outData[0]->getValues()[6].mValue.int_value);
}
} // namespace statsd
diff --git a/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp b/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp
new file mode 100644
index 000000000000..5c9636fa99cc
--- /dev/null
+++ b/cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "SurfaceflingerStatsPuller_test"
+
+#include "src/external/SurfaceflingerStatsPuller.h"
+
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class TestableSurfaceflingerStatsPuller : public SurfaceflingerStatsPuller {
+public:
+ TestableSurfaceflingerStatsPuller(const int tagId) : SurfaceflingerStatsPuller(tagId){};
+
+ void injectStats(const StatsProvider& statsProvider) {
+ mStatsProvider = statsProvider;
+ }
+};
+
+class SurfaceflingerStatsPullerTest : public ::testing::Test {
+public:
+ SurfaceflingerStatsPullerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ ~SurfaceflingerStatsPullerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+};
+
+TEST_F(SurfaceflingerStatsPullerTest, pullGlobalStats) {
+ surfaceflinger::SFTimeStatsGlobalProto proto;
+ proto.set_total_frames(1);
+ proto.set_missed_frames(2);
+ proto.set_client_composition_frames(2);
+ proto.set_display_on_time(4);
+
+ auto bucketOne = proto.add_present_to_present();
+ bucketOne->set_time_millis(2);
+ bucketOne->set_frame_count(4);
+ auto bucketTwo = proto.add_present_to_present();
+ bucketTwo->set_time_millis(4);
+ bucketTwo->set_frame_count(1);
+ auto bucketThree = proto.add_present_to_present();
+ bucketThree->set_time_millis(1000);
+ bucketThree->set_frame_count(1);
+ static constexpr int64_t expectedAnimationMillis = 12;
+ TestableSurfaceflingerStatsPuller puller(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+
+ puller.injectStats([&] {
+ return proto.SerializeAsString();
+ });
+ puller.ForceClearCache();
+ vector<std::shared_ptr<LogEvent>> outData;
+ puller.Pull(&outData);
+
+ ASSERT_EQ(1, outData.size());
+ EXPECT_EQ(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, outData[0]->GetTagId());
+ EXPECT_EQ(proto.total_frames(), outData[0]->getValues()[0].mValue.long_value);
+ EXPECT_EQ(proto.missed_frames(), outData[0]->getValues()[1].mValue.long_value);
+ EXPECT_EQ(proto.client_composition_frames(), outData[0]->getValues()[2].mValue.long_value);
+ EXPECT_EQ(proto.display_on_time(), outData[0]->getValues()[3].mValue.long_value);
+ EXPECT_EQ(expectedAnimationMillis, outData[0]->getValues()[4].mValue.long_value);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 67c704eb87fd..c503234a5765 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -187,9 +187,9 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
{getMockedDimensionKey(conditionTagId, 2, "222")};
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)).WillOnce(Return(ConditionState::kFalse));
+ EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
- EXPECT_CALL(*wizard, query(_, key2, _, _, _, _)).WillOnce(Return(ConditionState::kTrue));
+ EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
bucketStartTimeNs, bucketStartTimeNs);
@@ -396,6 +396,26 @@ TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
}
+TEST(CountMetricProducerTest, TestOneWeekTimeUnit) {
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_WEEK);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ int64_t oneDayNs = 24 * 60 * 60 * 1e9;
+ int64_t fiveWeeksNs = 5 * 7 * oneDayNs;
+
+ CountMetricProducer countProducer(
+ kConfigKey, metric, -1 /* meaning no condition */, wizard, oneDayNs, fiveWeeksNs);
+
+ int64_t fiveWeeksOneDayNs = fiveWeeksNs + oneDayNs;
+
+ EXPECT_EQ(fiveWeeksNs, countProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(4, countProducer.mCurrentBucketNum);
+ EXPECT_EQ(fiveWeeksOneDayNs, countProducer.getCurrentBucketEndTimeNs());
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index d2fd95c818cf..f30873b92afc 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -113,9 +113,9 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "222")};
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)).WillOnce(Return(ConditionState::kFalse));
+ EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
- EXPECT_CALL(*wizard, query(_, key2, _, _, _, _)).WillOnce(Return(ConditionState::kTrue));
+ EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index b9553a8fded8..b027e8e687db 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -79,8 +79,6 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) {
logEventMatcherIndex, eventMatcherWizard,
-1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
pullerManager);
- gaugeProducer.prepareFirstBucket();
-
EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, gaugeProducer.mCurrentBucketNum);
@@ -126,8 +124,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
-
vector<shared_ptr<LogEvent>> allData;
allData.clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
@@ -211,7 +207,6 @@ TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
logEventMatcherIndex, eventMatcherWizard,
-1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -303,7 +298,6 @@ TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -370,7 +364,6 @@ TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -431,7 +424,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
@@ -485,10 +477,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
dim->set_field(tagId);
dim->add_child()->set_field(1);
- dim = metric.mutable_dimensions_in_condition();
- dim->set_field(conditionTag);
- dim->add_child()->set_field(1);
-
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
atomMatcher.set_atom_id(tagId);
@@ -496,18 +484,14 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- EXPECT_CALL(*wizard, query(_, _, _, _, _, _))
+ EXPECT_CALL(*wizard, query(_, _, _))
.WillRepeatedly(
Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
- const vector<Matcher>& dimensionFields, const bool isSubsetDim,
- const bool isPartialLink,
- std::unordered_set<HashableDimensionKey>* dimensionKeySet) {
- dimensionKeySet->clear();
+ const bool isPartialLink) {
int pos[] = {1, 0, 0};
Field f(conditionTag, pos, 0);
HashableDimensionKey key;
key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
- dimensionKeySet->insert(key);
return ConditionState::kTrue;
}));
@@ -529,7 +513,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
@@ -538,9 +521,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
- EXPECT_EQ(1UL, key.getDimensionKeyInCondition().getValues().size());
- EXPECT_EQ(1000000, key.getDimensionKeyInCondition().getValues()[0].mValue.int_value);
-
EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
@@ -583,7 +563,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
Alert alert;
alert.set_id(101);
@@ -692,7 +671,6 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -777,7 +755,6 @@ TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index bf047520cc77..100220b730d7 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -52,7 +52,6 @@ TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -63,7 +62,7 @@ TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
int64_t bucketNum = 0;
int64_t metricId = 1;
- MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
false, false, {});
@@ -88,7 +87,6 @@ TEST(MaxDurationTrackerTest, TestStopAll) {
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -99,7 +97,7 @@ TEST(MaxDurationTrackerTest, TestStopAll) {
int64_t bucketNum = 0;
int64_t metricId = 1;
- MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
false, false, {});
@@ -124,7 +122,6 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -135,7 +132,7 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
int64_t bucketNum = 0;
int64_t metricId = 1;
- MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
false, false, {});
@@ -165,7 +162,6 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -176,7 +172,7 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
int64_t bucketNum = 0;
int64_t metricId = 1;
- MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
false, false, {});
@@ -202,7 +198,6 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
const HashableDimensionKey conditionDimKey = key1;
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey conditionKey1;
@@ -223,7 +218,7 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
int64_t eventStopTimeNs = conditionStops2 + 8 * NS_PER_SEC;
int64_t metricId = 1;
- MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
false, bucketStartTimeNs, 0, bucketStartTimeNs, bucketSizeNs, true,
false, {});
EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
@@ -246,7 +241,6 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
}
TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey conditionKey1;
@@ -273,7 +267,7 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
sp<AlarmMonitor> alarmMonitor;
sp<DurationAnomalyTracker> anomalyTracker =
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
- MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
true, false, {anomalyTracker});
@@ -295,7 +289,6 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
// This tests that we correctly compute the predicted time of an anomaly assuming that the current
// state continues forward as-is.
TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp) {
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey conditionKey1;
@@ -333,7 +326,7 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp) {
sp<AlarmMonitor> alarmMonitor;
sp<DurationAnomalyTracker> anomalyTracker =
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
- MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
true, false, {anomalyTracker});
@@ -381,7 +374,6 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp) {
// Suppose A starts, then B starts, and then A stops. We still need to set an anomaly based on the
// elapsed duration of B.
TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop) {
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey conditionKey1;
@@ -416,7 +408,7 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop) {
sp<AlarmMonitor> alarmMonitor;
sp<DurationAnomalyTracker> anomalyTracker =
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
- MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
true, false, {anomalyTracker});
@@ -434,4 +426,4 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop) {
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif \ No newline at end of file
+#endif
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 7c2b4236add8..1cd7bdbf7bb0 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -51,7 +51,6 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) {
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -62,7 +61,7 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) {
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
int64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, false, false, {});
@@ -84,7 +83,6 @@ TEST(OringDurationTrackerTest, TestDurationNested) {
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -94,7 +92,7 @@ TEST(OringDurationTrackerTest, TestDurationNested) {
int64_t bucketNum = 0;
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
- OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, false, false, {});
@@ -117,7 +115,6 @@ TEST(OringDurationTrackerTest, TestStopAll) {
{getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -127,7 +124,7 @@ TEST(OringDurationTrackerTest, TestStopAll) {
int64_t bucketNum = 0;
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
- OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, false, false, {});
@@ -147,7 +144,6 @@ TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -158,7 +154,7 @@ TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
int64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, false, false, {});
@@ -186,13 +182,12 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) {
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
- EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)) // #4
+ EXPECT_CALL(*wizard, query(_, key1, _)) // #4
.WillOnce(Return(ConditionState::kFalse));
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -203,7 +198,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) {
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
int64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, true, false, {});
@@ -224,13 +219,12 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
- EXPECT_CALL(*wizard, query(_, key1, _, _, _, _))
+ EXPECT_CALL(*wizard, query(_, key1, _))
.Times(2)
.WillOnce(Return(ConditionState::kFalse))
.WillOnce(Return(ConditionState::kTrue));
@@ -243,7 +237,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
int64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, true, false, {});
@@ -266,13 +260,12 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
- EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)) // #4
+ EXPECT_CALL(*wizard, query(_, key1, _)) // #4
.WillOnce(Return(ConditionState::kFalse));
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -282,7 +275,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
int64_t bucketNum = 0;
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
- OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, true, false, {});
@@ -306,7 +299,6 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- vector<Matcher> dimensionInCondition;
Alert alert;
alert.set_id(101);
alert.set_metric_id(1);
@@ -324,7 +316,7 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
sp<AlarmMonitor> alarmMonitor;
sp<DurationAnomalyTracker> anomalyTracker =
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
- OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, true, false, {anomalyTracker});
@@ -371,7 +363,6 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
}
TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp2) {
- vector<Matcher> dimensionInCondition;
Alert alert;
alert.set_id(101);
alert.set_metric_id(1);
@@ -387,7 +378,7 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp2) {
sp<DurationAnomalyTracker> anomalyTracker =
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
OringDurationTracker tracker(kConfigKey, metricId, DEFAULT_METRIC_DIMENSION_KEY, wizard, 1,
- dimensionInCondition,
+
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, true, false, {anomalyTracker});
@@ -415,7 +406,7 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp3) {
for (int j = 0; j < 3; j++) {
int64_t thresholdNs = j * bucketSizeNs + 5 * NS_PER_SEC;
for (int i = 0; i <= 7; ++i) {
- vector<Matcher> dimensionInCondition;
+
Alert alert;
alert.set_id(101);
alert.set_metric_id(1);
@@ -432,7 +423,7 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp3) {
sp<DurationAnomalyTracker> anomalyTracker =
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
OringDurationTracker tracker(kConfigKey, metricId, DEFAULT_METRIC_DIMENSION_KEY,
- wizard, 1, dimensionInCondition,
+ wizard, 1,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, true, false, {anomalyTracker});
@@ -472,7 +463,6 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- vector<Matcher> dimensionInCondition;
Alert alert;
alert.set_id(101);
alert.set_metric_id(1);
@@ -491,7 +481,7 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
sp<AlarmMonitor> alarmMonitor;
sp<DurationAnomalyTracker> anomalyTracker =
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
- OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
true /*nesting*/, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
bucketSizeNs, false, false, {anomalyTracker});
@@ -522,7 +512,6 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- vector<Matcher> dimensionInCondition;
Alert alert;
alert.set_id(101);
alert.set_metric_id(1);
@@ -541,7 +530,7 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
sp<AlarmMonitor> alarmMonitor;
sp<DurationAnomalyTracker> anomalyTracker =
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
- OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
+ OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
true /*nesting*/, bucketStartTimeNs, 0, bucketStartTimeNs,
bucketSizeNs, false, false, {anomalyTracker});
@@ -589,4 +578,4 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif \ No newline at end of file
+#endif
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 2262c76e64f9..4b9d0c0ca718 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -105,7 +105,6 @@ class ValueMetricProducerTestHelper {
kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- valueProducer->prepareFirstBucket();
return valueProducer;
}
@@ -125,7 +124,6 @@ class ValueMetricProducerTestHelper {
new ValueMetricProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer->prepareFirstBucket();
valueProducer->mCondition = ConditionState::kFalse;
return valueProducer;
}
@@ -169,7 +167,6 @@ TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1, startTimeBase,
22, pullerManager);
- valueProducer.prepareFirstBucket();
EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
@@ -199,7 +196,6 @@ TEST(ValueMetricProducerTest, TestFirstBucket) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1, 5,
600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager);
- valueProducer.prepareFirstBucket();
EXPECT_EQ(600500000000, valueProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, valueProducer.mCurrentBucketNum);
@@ -381,7 +377,6 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- valueProducer->prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -670,7 +665,6 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -728,7 +722,6 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -779,7 +772,6 @@ TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -854,7 +846,6 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -897,7 +888,6 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
valueProducer.mCondition = ConditionState::kFalse;
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
@@ -972,7 +962,6 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1 /*not pulled*/,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
@@ -1269,7 +1258,6 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1314,7 +1302,6 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1361,7 +1348,6 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1412,7 +1398,6 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1458,7 +1443,6 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1532,7 +1516,6 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -2081,7 +2064,6 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucket2StartTimeNs,
bucket2StartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
valueProducer.mCondition = ConditionState::kFalse;
// Event should be skipped since it is from previous bucket.
@@ -2862,7 +2844,6 @@ TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
ProtoOutputStream output;
std::set<string> strSet;
@@ -2905,7 +2886,6 @@ TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -2969,7 +2949,6 @@ TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
ProtoOutputStream output;
std::set<string> strSet;
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index 97c107228f9c..329e39fc4eff 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -26,11 +26,9 @@ namespace statsd {
class MockConditionWizard : public ConditionWizard {
public:
- MOCK_METHOD6(query,
+ MOCK_METHOD3(query,
ConditionState(const int conditionIndex, const ConditionKey& conditionParameters,
- const vector<Matcher>& dimensionFields,
- const bool isSubsetDim, const bool isPartialLink,
- std::unordered_set<HashableDimensionKey>* dimensionKeySet));
+ const bool isPartialLink));
};
class MockStatsPullerManager : public StatsPullerManager {
@@ -55,4 +53,4 @@ void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher);
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
new file mode 100644
index 000000000000..c89ffea85709
--- /dev/null
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -0,0 +1,356 @@
+/*
+ * 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 <gtest/gtest.h>
+#include "state/StateManager.h"
+#include "state/StateTracker.h"
+#include "state/StateListener.h"
+
+#include "tests/statsd_test_util.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Mock StateListener class for testing.
+ * Stores primary key and state pairs.
+ */
+class TestStateListener : public virtual StateListener {
+public:
+ TestStateListener(){};
+
+ virtual ~TestStateListener(){};
+
+ struct Update {
+ Update(const HashableDimensionKey& key, int state) : mKey(key), mState(state){};
+ HashableDimensionKey mKey;
+ int mState;
+ };
+
+ std::vector<Update> updates;
+
+ void onStateChanged(int stateAtomId, const HashableDimensionKey& primaryKey, int oldState,
+ int newState) {
+ updates.emplace_back(primaryKey, newState);
+ }
+};
+
+// START: build event functions.
+// State with no primary fields - ScreenStateChanged
+std::shared_ptr<LogEvent> buildScreenEvent(int state) {
+ std::shared_ptr<LogEvent> event =
+ std::make_shared<LogEvent>(android::util::SCREEN_STATE_CHANGED, 1000 /*timestamp*/);
+ event->write((int32_t)state);
+ event->init();
+ return event;
+}
+
+// State with one primary field - UidProcessStateChanged
+std::shared_ptr<LogEvent> buildUidProcessEvent(int uid, int state) {
+ std::shared_ptr<LogEvent> event =
+ std::make_shared<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, 1000 /*timestamp*/);
+ event->write((int32_t)uid);
+ event->write((int32_t)state);
+ event->init();
+ return event;
+}
+
+// State with multiple primary fields - OverlayStateChanged
+std::shared_ptr<LogEvent> buildOverlayEvent(int uid, const std::string& packageName, int state) {
+ std::shared_ptr<LogEvent> event =
+ std::make_shared<LogEvent>(android::util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
+ event->write((int32_t)uid);
+ event->write(packageName);
+ event->write(true); // using_alert_window
+ event->write((int32_t)state);
+ event->init();
+ return event;
+}
+
+std::shared_ptr<LogEvent> buildIncorrectOverlayEvent(int uid, const std::string& packageName, int state) {
+ std::shared_ptr<LogEvent> event =
+ std::make_shared<LogEvent>(android::util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
+ event->write((int32_t)uid);
+ event->write(packageName);
+ event->write((int32_t)state);
+ event->init();
+ return event;
+}
+// END: build event functions.
+
+// START: get primary key functions
+void getUidProcessKey(int uid, HashableDimensionKey* key) {
+ int pos1[] = {1, 0, 0};
+ Field field1(27 /* atom id */, pos1, 0 /* depth */);
+ Value value1((int32_t)uid);
+
+ key->addValue(FieldValue(field1, value1));
+}
+
+void getOverlayKey(int uid, string packageName, HashableDimensionKey* key) {
+ int pos1[] = {1, 0, 0};
+ int pos2[] = {2, 0, 0};
+
+ Field field1(59 /* atom id */, pos1, 0 /* depth */);
+ Field field2(59 /* atom id */, pos2, 0 /* depth */);
+
+ Value value1((int32_t)uid);
+ Value value2(packageName);
+
+ key->addValue(FieldValue(field1, value1));
+ key->addValue(FieldValue(field2, value2));
+}
+// END: get primary key functions
+
+TEST(StateListenerTest, TestStateListenerWeakPointer) {
+ sp<TestStateListener> listener = new TestStateListener();
+ wp<TestStateListener> wListener = listener;
+ listener = nullptr; // let go of listener
+ EXPECT_TRUE(wListener.promote() == nullptr);
+}
+
+TEST(StateManagerTest, TestStateManagerGetInstance) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager& mgr = StateManager::getInstance();
+
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+}
+
+/**
+ * Test registering listeners to StateTrackers
+ *
+ * - StateManager will create a new StateTracker if it doesn't already exist
+ * and then register the listener to the StateTracker.
+ * - If a listener is already registered to a StateTracker, it is not added again.
+ * - StateTrackers are only created for atoms that are state atoms.
+ */
+TEST(StateTrackerTest, TestRegisterListener) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ sp<TestStateListener> listener2 = new TestStateListener();
+ StateManager mgr;
+
+ // Register listener to non-existing StateTracker
+ EXPECT_EQ(0, mgr.getStateTrackersCount());
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Register listener to existing StateTracker
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(2, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Register already registered listener to existing StateTracker
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(2, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Register listener to non-state atom
+ mgr.registerListener(android::util::BATTERY_LEVEL_CHANGED, listener2);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+}
+
+/**
+ * Test unregistering listeners from StateTrackers
+ *
+ * - StateManager will unregister listeners from a StateTracker only if the
+ * StateTracker exists and the listener is registered to the StateTracker.
+ * - Once all listeners are removed from a StateTracker, the StateTracker
+ * is also removed.
+ */
+TEST(StateTrackerTest, TestUnregisterListener) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ sp<TestStateListener> listener2 = new TestStateListener();
+ StateManager mgr;
+
+ // Unregister listener from non-existing StateTracker
+ EXPECT_EQ(0, mgr.getStateTrackersCount());
+ mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ EXPECT_EQ(0, mgr.getStateTrackersCount());
+ EXPECT_EQ(-1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Unregister non-registered listener from existing StateTracker
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+ mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener2);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Unregister second-to-last listener from StateTracker
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2);
+ mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ EXPECT_EQ(1, mgr.getStateTrackersCount());
+ EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+
+ // Unregister last listener from StateTracker
+ mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener2);
+ EXPECT_EQ(0, mgr.getStateTrackersCount());
+ EXPECT_EQ(-1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+}
+
+/**
+ * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
+ * updates listener for states without primary keys.
+ */
+TEST(StateTrackerTest, TestStateChangeNoPrimaryFields) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+
+ // log event
+ std::shared_ptr<LogEvent> event =
+ buildScreenEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ mgr.onLogEvent(*event);
+
+ // check listener was updated
+ EXPECT_EQ(1, listener1->updates.size());
+ EXPECT_EQ(DEFAULT_DIMENSION_KEY, listener1->updates[0].mKey);
+ EXPECT_EQ(2, listener1->updates[0].mState);
+
+ // check StateTracker was updated by querying for state
+ HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY;
+ EXPECT_EQ(2, mgr.getState(android::util::SCREEN_STATE_CHANGED, queryKey));
+}
+
+/**
+ * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
+ * updates listener for states with primary keys.
+ */
+TEST(StateTrackerTest, TestStateChangeOnePrimaryField) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::UID_PROCESS_STATE_CHANGED, listener1);
+
+ // log event
+ std::shared_ptr<LogEvent> event = buildUidProcessEvent(
+ 1000,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
+ mgr.onLogEvent(*event);
+
+ // check listener was updated
+ EXPECT_EQ(1, listener1->updates.size());
+ EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(1002, listener1->updates[0].mState);
+
+ // check StateTracker was updated by querying for state
+ HashableDimensionKey queryKey;
+ getUidProcessKey(1000, &queryKey);
+ EXPECT_EQ(1002, mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey));
+}
+
+TEST(StateTrackerTest, TestStateChangeMultiplePrimaryFields) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener1);
+
+ // log event
+ std::shared_ptr<LogEvent> event = buildOverlayEvent(1000, "package1", 1); // state: ENTERED
+ mgr.onLogEvent(*event);
+
+ // check listener update
+ EXPECT_EQ(1, listener1->updates.size());
+ EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(1, listener1->updates[0].mState);
+}
+
+/**
+ * Test StateManager's onLogEvent and StateListener's onStateChanged
+ * when there is an error extracting state from log event. Listener is not
+ * updated of state change.
+ */
+TEST(StateTrackerTest, TestStateChangeEventError) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener1);
+
+ // log event
+ std::shared_ptr<LogEvent> event =
+ buildIncorrectOverlayEvent(1000, "package1", 1); // state: ENTERED
+ mgr.onLogEvent(*event);
+
+ // check listener update
+ EXPECT_EQ(0, listener1->updates.size());
+}
+
+TEST(StateTrackerTest, TestStateQuery) {
+ sp<TestStateListener> listener1 = new TestStateListener();
+ sp<TestStateListener> listener2 = new TestStateListener();
+ sp<TestStateListener> listener3 = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+ mgr.registerListener(android::util::UID_PROCESS_STATE_CHANGED, listener2);
+ mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener3);
+
+ std::shared_ptr<LogEvent> event1 = buildUidProcessEvent(
+ 1000,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
+ std::shared_ptr<LogEvent> event2 = buildUidProcessEvent(
+ 1001,
+ android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE); // state value: 1003
+ std::shared_ptr<LogEvent> event3 = buildUidProcessEvent(
+ 1002,
+ android::app::ProcessStateEnum::PROCESS_STATE_PERSISTENT); // state value: 1000
+ std::shared_ptr<LogEvent> event4 = buildUidProcessEvent(
+ 1001,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
+ std::shared_ptr<LogEvent> event5 =
+ buildScreenEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON); // state value:
+ std::shared_ptr<LogEvent> event6 = buildOverlayEvent(1000, "package1", 1);
+ std::shared_ptr<LogEvent> event7 = buildOverlayEvent(1000, "package2", 2);
+
+ mgr.onLogEvent(*event1);
+ mgr.onLogEvent(*event2);
+ mgr.onLogEvent(*event3);
+ mgr.onLogEvent(*event5);
+ mgr.onLogEvent(*event5);
+ mgr.onLogEvent(*event6);
+ mgr.onLogEvent(*event7);
+
+ // Query for UidProcessState of uid 1001
+ HashableDimensionKey queryKey1;
+ getUidProcessKey(1001, &queryKey1);
+ EXPECT_EQ(1003, mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
+
+ // Query for UidProcessState of uid 1004 - not in state map
+ HashableDimensionKey queryKey2;
+ getUidProcessKey(1004, &queryKey2);
+ EXPECT_EQ(-1,
+ mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey2)); // default state
+
+ // Query for UidProcessState of uid 1001 - after change in state
+ mgr.onLogEvent(*event4);
+ EXPECT_EQ(1002, mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
+
+ // Query for ScreenState
+ EXPECT_EQ(2, mgr.getState(android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
+
+ // Query for OverlayState of uid 1000, package name "package2"
+ HashableDimensionKey queryKey3;
+ getOverlayKey(1000, "package2", &queryKey3);
+ EXPECT_EQ(2, mgr.getState(android::util::OVERLAY_STATE_CHANGED, queryKey3));
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tools/dogfood/Android.bp b/cmds/statsd/tools/dogfood/Android.bp
deleted file mode 100644
index bb494a6025af..000000000000
--- a/cmds/statsd/tools/dogfood/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2017 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.
-//
-//
-
-android_app {
- name: "StatsdDogfood",
- platform_apis: true,
-
- srcs: ["src/**/*.java"],
-
- resource_dirs: ["res"],
- static_libs: [
- "platformprotoslite",
- "statsdprotolite",
- ],
-
- privileged: true,
- dex_preopt: {
- enabled: false,
- },
- certificate: "platform",
- optimize: {
- enabled: false,
- },
-}
diff --git a/cmds/statsd/tools/dogfood/AndroidManifest.xml b/cmds/statsd/tools/dogfood/AndroidManifest.xml
deleted file mode 100644
index 52673fbdcf92..000000000000
--- a/cmds/statsd/tools/dogfood/AndroidManifest.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.statsd.dogfood"
- android:sharedUserId="android.uid.system"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-permission android:name="android.permission.DUMP" />
-
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name"
- android:launchMode="singleTop" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
-
- <service android:name=".MainActivity$ReceiverIntentService" android:exported="true" />
- </application>
-</manifest>
diff --git a/cmds/statsd/tools/dogfood/res/drawable-hdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 55621cc1074f..000000000000
--- a/cmds/statsd/tools/dogfood/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/drawable-mdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 11ec2068be19..000000000000
--- a/cmds/statsd/tools/dogfood/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/drawable-xhdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 7c02b784aa5d..000000000000
--- a/cmds/statsd/tools/dogfood/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/drawable-xxhdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 915d91441349..000000000000
--- a/cmds/statsd/tools/dogfood/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/layout/activity_main.xml b/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
deleted file mode 100644
index 784ed40ce2c2..000000000000
--- a/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
+++ /dev/null
@@ -1,162 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <Button
- android:id="@+id/push_config"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_green_light"
- android:text="@string/push_config"/>
- <Button
- android:id="@+id/set_receiver"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_green_light"
- android:text="@string/set_receiver"/>
- <Button
- android:id="@+id/remove_receiver"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_green_light"
- android:text="@string/remove_receiver"/>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/app_a_wake_lock_acquire1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_a_get_wl1"/>
- <Button android:id="@+id/app_a_wake_lock_release1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_a_release_wl1"/>
- </LinearLayout>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/app_a_wake_lock_acquire2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_a_get_wl2"/>
- <Button android:id="@+id/app_a_wake_lock_release2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_a_release_wl2"/>
- </LinearLayout>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/app_b_wake_lock_acquire1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_b_get_wl1"/>
- <Button android:id="@+id/app_b_wake_lock_release1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_b_release_wl1"/>
- </LinearLayout>
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/app_b_wake_lock_acquire2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_b_get_wl2"/>
- <Button android:id="@+id/app_b_wake_lock_release2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_b_release_wl2"/>
- </LinearLayout>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/plug"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/plug"/>
-
- <Button android:id="@+id/unplug"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/unplug"/>
- </LinearLayout>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/screen_on"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/screen_on"/>
-
- <Button android:id="@+id/screen_off"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/screen_off"/>
- </LinearLayout>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/custom_start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/custom_start" />
-
- <Button
- android:id="@+id/custom_stop"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/custom_stop" />
- </LinearLayout>
-
- <Button android:id="@+id/dump"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_purple"
- android:text="@string/dump"/>
-
- <TextView
- android:id="@+id/header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/report_header"/>
-
- <TextView
- android:id="@+id/report_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
-</ScrollView> \ No newline at end of file
diff --git a/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config b/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
deleted file mode 100644
index d05006124994..000000000000
--- a/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
+++ /dev/null
@@ -1,109 +0,0 @@
-¹ÓõÕ¯¤”årÝèåâÕ»éÉ7¬ìŸ‘Ψê­.–´šÄÁŒç¶ÚšäÑùôºZªÑ€¸ëÐé­í‘˜‹Ý™ûÆŽ6ˆ™ÁÖ΂õ›Ã¥¼à¨É—ÿQÝàåÈ߀äÍ@ÆÙÑ„ÓІ„èѿ̲±™¨lŸÄ€ìúˆÖ­ü¶ú̳Šéâ‡ãà§ØÈË´Ù%ó­ÓÚ«¹¼ÜyÛ®±ë¸«”º?­¹•繡¸Œ€â鿨ŒÙœ®‘)çæ©Á”§äéîÀ‚Ò®ö‡.ÐÙ•°‹ÁÈy"'(WòóÀ–ðßæ¬ùÕàÀ™ýëZ”ÔÆ™Ž¤š¹»"
- (2!ûÄߪæþªâÚ 
-V¢¦€¡’€Ç€¡ùÕàÀ™ýëZÈ‹ÄÂë¢Ä¯Ø"
- (2 ª–¨Œ×ÿ¹¡k 
-V‡úÌòá㿘>ùÕàÀ™ýëZáž‹â‘Ý»ä"
- (2!÷‘–ä–Œ¿¯ 
-WØõé¼ÃóÀàþùÕàÀ™ýëZ°ÔØùΣ‘¯"
- (2!Ïä†÷ɯ 
-VÚœäÌþ½¬jùÕàÀ™ýëZ³Ö‰Ó¾ ½Ñ"
- (2!Ÿ¡ªˆëôùÇ 
-V¨¾ñ≎̅ùÕàÀ™ýëZ“Ðåÿèåò?"
- (2!½šòÐ䤿Œ 
-U…£²†µÜ‡‘_ùÕàÀ™ýëZñîôÒ‡¤´†z"
- (2!é’¬¸ç¼‡Óª 
-K‘ã´¶üÅçúñ±Ë壆¨D”ÔÆ™Ž¤š¹»"
-#(2ûÄߪæþªâÚ#Ië§ì·ºê•Æúñ±Ë壆¨DÈ‹ÄÂë¢Ä¯Ø"
-#(2ª–¨Œ×ÿ¹¡k#JÙ¢Öúƒ†ðúñ±Ë壆¨Dáž‹â‘Ý»ä"
-#(2÷‘–ä–Œ¿¯#JãýØåóªü)úñ±Ë壆¨D°ÔØùΣ‘¯"
-#(2Ïä†÷ɯ#KËÅÝÇž¹Åãúñ±Ë壆¨D³Ö‰Ó¾ ½Ñ"
-#(2Ÿ¡ªˆëôùÇ#Jɳ¸ó€„ø‘Ãúñ±Ë壆¨D“Ðåÿèåò?"
-#(2½šòÐ䤿Œ#J•–ó«ðô¤Þïúñ±Ë壆¨DñîôÒ‡¤´†z"
-#(2é’¬¸ç¼‡Óª#J•ºÔ¯•…Î’:›ºô¿Úó¾kŒÓÜ¢¾ÌÊ"
-(2ûÄߪæþªâÚI»ÓòÓí‰àÖ
-›ºô¿Úó¾kǮ›ŸÊŸäâ"
-(2ª–¨Œ×ÿ¹¡kJÖÐük÷y›ºô¿Úó¾kÿ‚¾žÃ“’§õ"
-(2÷‘–ä–Œ¿¯JøÿÊ“åøË¨›ºô¿Úó¾k˜ý˜‘¢ŒÐÀI"
-(2Ïä†÷ɯKõ­ß°—’ì¾×›ºô¿Úó¾kì‘áÒîŸÙÍá"
-(2Ÿ¡ªˆëôùÇJà¸ëòä¥û݈›ºô¿Úó¾kôé‹¿¿¸ßÄ"
-(2½šòÐ䤿ŒJУŒð†¬µÙ›ºô¿Úó¾k‰±Öйˆ–Ôõ"
-(2é’¬¸ç¼‡ÓªK—ÍË é÷ÐM鮣öü©µŒÓÜ¢¾ÌÊ"
-(2ûÄߪæþªâÚJÌŽë á«¡´{鮣öü©µǮ›ŸÊŸäâ"
-(2ª–¨Œ×ÿ¹¡kL˜†ŒÏØì¡‹³鮣öü©µÿ‚¾žÃ“’§õ"
-(2÷‘–ä–Œ¿¯Ká°Ñàƒ½†¶ý鮣öü©µ˜ý˜‘¢ŒÐÀI"
-(2Ïä†÷ɯKÛ”Ÿò§…ÂÁY鮣öü©µì‘áÒîŸÙÍá"
-(2Ÿ¡ªˆëôùÇKϜݗÞç±ù¥鮣öü©µôé‹¿¿¸ßÄ"
-(2½šòÐ䤿ŒKÚÖ•·‰­–B鮣öü©µ‰±Öйˆ–Ôõ"
-(2é’¬¸ç¼‡Óª,Ä®öèÀƒ‘âÌ¥•€†ÜÖ×AÐÙ•°‹ÁÈy"
-(€õ»•÷¾ÓçȪŠéñðȃŹ~”‰àÉ­®¶f"(2é’¬¸ç¼‡Óª2½šòÐ䤿Œ2Ÿ¡ªˆëôùÇLشͼá™þþæ¿É¶ˆœ‚æð±ûÄߪæþªâÚ"
--(2ûÄߪæþªâÚ-JÉ¥˜‘Ûüˆ‹ò¿É¶ˆœ‚æð±ª–¨Œ×ÿ¹¡k"
--(2ª–¨Œ×ÿ¹¡k-L¡©äÞ¨ô¶ø½¿É¶ˆœ‚æð±÷‘–ä–Œ¿¯"
--(2÷‘–ä–Œ¿¯-L‡õÇþ¡¾ÚÈþ¿É¶ˆœ‚æð±Ïä†÷ɯ"
--(2Ïä†÷ɯ-L—î«ãïÚ½û¬¿É¶ˆœ‚æð±Ÿ¡ªˆëôùÇ"
--(2Ÿ¡ªˆëôùÇ-LñÍý‚ÿô­¿É¶ˆœ‚æð±½šòÐ䤿Œ"
--(2½šòÐ䤿Œ-K‹òʰ«»íè|¿É¶ˆœ‚æð±é’¬¸ç¼‡Óª"
--(2é’¬¸ç¼‡Óª-"9äëæÚòœ§=̨…¥”ìãÏ‘N ÐÙ•°‹ÁÈy* ‘N0@":­šˆž‚έñÐ̨…¥”ìãÏ‘N ÐÙ•°‹ÁÈy* ‘N0@":ù»Žôç¾ãˆÐ̨…¥”ìãÏ‘N ÐÙ•°‹ÁÈy* ‘N0@"9›™›ŸÝ†—ãS̨…¥”ìãÏ‘N ÐÙ•°‹ÁÈy* ‘N0@":‹ããùŸáŽôºßñ¼ûÌ•˜“N ÐÙ•°‹ÁÈy* “N0@":ç΀àë Œƒôºßñ¼ûÌ•˜“N ÐÙ•°‹ÁÈy* “N0@":™˜µøÖ²Äìõôºßñ¼ûÌ•˜“N ÐÙ•°‹ÁÈy* “N0@":¬Öœ¥¥ÃÆŒÑôºßñ¼ûÌ•˜“N ÐÙ•°‹ÁÈy* “N0@"5ôÇ™±¶Ï¢‘ò•™ÔéŠñ˜Èu›N ÐÙ•°‹ÁÈy*›N0@"4«÷µÿ󲂜e•™ÔéŠñ˜Èu›N ÐÙ•°‹ÁÈy*›N0@"4å¢úˆÑÙúý•™ÔéŠñ˜Èu›N ÐÙ•°‹ÁÈy*›N0@"+ž—Õõ‰î¶±~‡î‚ÒÔÊ´ËœN ÐÙ•°‹ÁÈy0@",‘ó‚³ïÙù¦‚‡î‚ÒÔÊ´ËœN ÐÙ•°‹ÁÈy0@"+òßù¥·«Äà;‡î‚ÒÔÊ´ËœN ÐÙ•°‹ÁÈy0@",ÓûÅñÒ¢ô§Â‡î‚ÒÔÊ´ËœN ÐÙ•°‹ÁÈy0@"+¨²°žò³ƒ¨R‡î‚ÒÔÊ´ËœN ÐÙ•°‹ÁÈy0@"+ÞìøݱþÖq‡î‚ÒÔÊ´ËœN ÐÙ•°‹ÁÈy0@",͉šæÜ­ŽÄÀ‡î‚ÒÔÊ´ËœN ÐÙ•°‹ÁÈy0@"3Ä»±ê¾¸ô°˜þËÉÇåãÃ2 ÐÙ•°‹ÁÈy*0@"‰ѽËñɤ¡™a˜þËÉÇåãÃ2 ”‰àÉ­®¶f*0:é’¬¸ç¼‡Óª:½šòÐ䤿Œ:Ÿ¡ªˆëôùÇ@":ÃêåÒýéó¦ï‘ŽÁ°×ËÇÅß–N ÐÙ•°‹ÁÈy* –N0@":Àš‚ÑÀí£Ï‹‘ŽÁ°×ËÇÅß–N ÐÙ•°‹ÁÈy* –N0@"9¾¢ðÛßÒëéø›²Ö·ÔÈšN ÐÙ•°‹ÁÈy* šN0@"9÷´ç鼯Š~½ ¤„¹®Ð§¨˜N ÐÙ•°‹ÁÈy* ˜N0@2YÝæÆËò ‚ú‘»óÓ¤ãËÕ”ÔÆ™Ž¤š¹»"!ûÄߪæþªâÚ 
-(2
- 82X°öòΪáŠþ„»óÓ¤ãËÕÈ‹ÄÂë¢Ä¯Ø" ª–¨Œ×ÿ¹¡k 
-(2
- 82X°ç¦ùºŒó·0»óÓ¤ãËÕáž‹â‘Ý»ä"!÷‘–ä–Œ¿¯ 
-(2
- 82Yôæï°Þ¼  ”»óÓ¤ãËÕ°ÔØùΣ‘¯"!Ïä†÷ɯ 
-(2
- 82Y¡Î°Ãåüý»óÓ¤ãËÕ³Ö‰Ó¾ ½Ñ"!Ÿ¡ªˆëôùÇ 
-(2
- 82XÕ¤ô®Ã£ÇÓÈ»óÓ¤ãËÕ“Ðåÿèåò?"!½šòÐ䤿Œ 
-(2
- 82XÖÂªßøæÌÊ»óÓ¤ãËÕñîôÒ‡¤´†z"!é’¬¸ç¼‡Óª 
-(2
- 825’ÌíûÍõ÷Æ­»óÓ¤ãËÕ®Èùé€ù’±W(2
- 82X²¹÷߆ŒÀ¶`»óÓ¤ãËÕ”ÔÆ™Ž¤š¹»"!ûÄߪæþªâÚ 
-(2
- 82W÷ÞŸÉÔ ëÍd»óÓ¤ãËÕÈ‹ÄÂë¢Ä¯Ø" ª–¨Œ×ÿ¹¡k 
-(2
- 82XäÁš´¤·ñì.»óÓ¤ãËÕáž‹â‘Ý»ä"!÷‘–ä–Œ¿¯ 
-(2
- 82YîæÍçâ»óÓ¤ãËÕ°ÔØùΣ‘¯"!Ïä†÷ɯ 
-(2
- 82Y˜²Ì´×³ìóÓ¤ãËÕ³Ö‰Ó¾ ½Ñ"!Ÿ¡ªˆëôùÇ 
-(2
- 82W¾¯†‘§È“¿P»óÓ¤ãËÕ“Ðåÿèåò?"!½šòÐ䤿Œ 
-(2
- 82XÂÀ¶òšË˜‚ð»óÓ¤ãËÕñîôÒ‡¤´†z"!é’¬¸ç¼‡Óª 
-(2
- 82U—îïÛ²¸¸†µ»óÓ¤ãËÕ”ÔÆ™Ž¤š¹»"!ûÄߪæþªâÚ 
-(2 
-82Tû¯ûû²¶ýñ§»óÓ¤ãËÕÈ‹ÄÂë¢Ä¯Ø" ª–¨Œ×ÿ¹¡k 
-(2 
-82T†ñù™ŸÈ¨«»óÓ¤ãËÕáž‹â‘Ý»ä"!÷‘–ä–Œ¿¯ 
-(2 
-82T҈πŸ¯‰ŠD»óÓ¤ãËÕ°ÔØùΣ‘¯"!Ïä†÷ɯ 
-(2 
-82Uš¤Ë„阿ö†»óÓ¤ãËÕ³Ö‰Ó¾ ½Ñ"!Ÿ¡ªˆëôùÇ 
-(2 
-82SË©ËÞ¯öÈÞ&»óÓ¤ãËÕ“Ðåÿèåò?"!½šòÐ䤿Œ 
-(2 
-82TάóýᔺèÞ»óÓ¤ãËÕñîôÒ‡¤´†z"!é’¬¸ç¼‡Óª 
-(2 
-82#àšÉ±ûÿ±»óÓ¤ãËÕ®Èùé€ù’±W(82#ÞžÞïƒ÷“…±œ–±ÃŸ€ÀâFÐÙ•°‹ÁÈy(82"䣞ƒƒ¿Èòrœ–±ÃŸ€ÀâFÐÙ•°‹ÁÈy(82*¦‚ó©ÂÊÓŒ3œ–±ÃŸ€ÀâFÐÙ•°‹ÁÈy(2%82*ÅМ½à®ÄŠœ–±ÃŸ€ÀâFÐÙ•°‹ÁÈy(2%82"‡è‘²†ÙÓÂ+œ–±ÃŸ€ÀâFÐÙ•°‹ÁÈy(82J›»ÜŽáø©ÔӈƄת¶£«ŒÓÜ¢¾ÌÊ"ûÄߪæþªâÚ'(2'82H®Ñä‚Òš„ÝqˆÆ„ת¶£«Ǯ›ŸÊŸäâ"ª–¨Œ×ÿ¹¡k'(2'82JêýÂÄ…Œ™ÉˆƄת¶£«ÿ‚¾žÃ“’§õ"÷‘–ä–Œ¿¯'(2'82Iâ븛ÚðÖóˆÆ„ת¶£«˜ý˜‘¢ŒÐÀI"Ïä†÷ɯ'(2'82Iÿ±å¨ ïÉ­KˆÆ„ת¶£«ì‘áÒîŸÙÍá"Ÿ¡ªˆëôùÇ'(2'82Hý©ëÞ¥é÷“\ˆÆ„ת¶£«ôé‹¿¿¸ßÄ"½šòÐ䤿Œ'(2'82JÁ°Õ즊ý…¯ˆÆ„ת¶£«‰±Öйˆ–Ôõ"é’¬¸ç¼‡Óª'(2'82ƒ˜Êã•ÿÊÙÚ·æúŸÌ½‚¡”‰àÉ­®¶f"é’¬¸ç¼‡Óª"½šòÐ䤿Œ"Ÿ¡ªˆëôùÇ(282‚ÊùÑèÂóžàY·æúŸÌ½‚¡”‰àÉ­®¶f"é’¬¸ç¼‡Óª"½šòÐ䤿Œ"Ÿ¡ªˆëôùÇ(282MÚËñ´ä‡¼Ä'ª ÿçû¤é刌ÓÜ¢¾ÌÊ"ûÄߪæþªâÚ(2
-82LŽÏ—ꤦݯ5ª ÿçû¤éåˆǮ›ŸÊŸäâ"ª–¨Œ×ÿ¹¡k(2
-82Nø‚ÍÁœÆÚª ÿçû¤éåˆÿ‚¾žÃ“’§õ"÷‘–ä–Œ¿¯(2
-82LŸ¿ŽöåèÆ)ª ÿçû¤é刘ý˜‘¢ŒÐÀI"Ïä†÷ɯ(2
-82NþÝÒÿ§Ù¡±˜ª ÿçû¤éåˆì‘áÒîŸÙÍá"Ÿ¡ªˆëôùÇ(2
-82M³­Ñ×饊ÿ¦ª ÿçû¤éåˆôé‹¿¿¸ßÄ"½šòÐ䤿Œ(2
-82M–ÎÜ‹ó¯Ë„ª ÿçû¤é刉±Öйˆ–Ôõ"é’¬¸ç¼‡Óª(2
-82ƒÍê´ýÞÁöª ÿçû¤é刔‰àÉ­®¶f"é’¬¸ç¼‡Óª"½šòÐ䤿Œ"Ÿ¡ªˆëôùÇ(282,Ü›ä¤ö¸Åˆºª ÿçû¤éåˆÐÙ•°‹ÁÈy(282+Ù¼‡úýõ‰—êâÓ»ä¾ÙÙ9ÐÙ•°‹ÁÈy(282.ƒÚæË›Õ²“^âÓ»ä¾ÙÙ9ÐÙ•°‹ÁÈy(2
-82/òìšÀ·ÄŒÃ#óª·Žð–äÑŠÐÙ•°‹ÁÈy(2
-82+¢ØþËÄÝßíyóª·Žð–äÑŠÐÙ•°‹ÁÈy(282"йʢäÞ†#½³ úùš±KÐÙ•°‹ÁÈy(82I¾Œ…û±ªÓþν³ úùš±KŒÓÜ¢¾ÌÊ"ûÄߪæþªâÚ(282HÞ­ûÅŠëŽî½³ úùš±KǮ›ŸÊŸäâ"ª–¨Œ×ÿ¹¡k(282HÚÇÍý›ôÍô_½³ úùš±Kÿ‚¾žÃ“’§õ"÷‘–ä–Œ¿¯(282Gá”ܰ§¼Üï{½³ úùš±K˜ý˜‘¢ŒÐÀI"Ïä†÷ɯ(282IŒú’ìÌšŒÿ½³ úùš±Kì‘áÒîŸÙÍá"Ÿ¡ªˆëôùÇ(282HðÒ¬¼ïˆâ½³ úùš±Kôé‹¿¿¸ßÄ"½šòÐ䤿Œ(282Hˆ¼ÂÁŒ‚ªŠE½³ úùš±K‰±Öйˆ–Ôõ"é’¬¸ç¼‡Óª(282 ðÚžºÖèà몖¨Œ×ÿ¹¡k(282"…ïèÙŸåóþÎûÄߪæþªâÚ(282!ÆÉ¨‡âž¯‰÷‘–ä–Œ¿¯(282"Õ™õê×Ì·›‹Ïä†÷ɯ(282!Þíó¾ó¿ÚªˆëôùÇ(282!ž¥ÌÔѾۛL½šòÐ䤿Œ(282!„±ÂææÄÁOé’¬¸ç¼‡Óª(282+¦‚ýª¬¢˜þǪ–¨Œ×ÿ¹¡kÐÙ•°‹ÁÈy(282+Ó®¿Œïɳ=ûÄߪæþªâÚÐÙ•°‹ÁÈy(282+ØŽ„Øø¨²c÷‘–ä–Œ¿¯ÐÙ•°‹ÁÈy(282,ýŒ®ê£ÀËŠÏä†÷ɯÐÙ•°‹ÁÈy(282+’ÐÝç’묩uŸ¡ªˆëôùÇÐÙ•°‹ÁÈy(282,ÌÅ„„ŒúÔÞ ½šòÐ䤿ŒÐÙ•°‹ÁÈy(282,ÿªØ¦ƒ®èý»é’¬¸ç¼‡ÓªÐÙ•°‹ÁÈy(282#©Ô†«¹ÛÈÊœä”Û›ÅËèÄÐÙ•°‹ÁÈy(82,‡¼ã™“ЧÓœä”Û›ÅËèÄÐÙ•°‹ÁÈy(2 82#ëÜÄêÖª©ÞùÃýب°Ï=ÐÙ•°‹ÁÈy(82I¬Í˜ÝïÚÈéùÃýب°Ï=ŒÓÜ¢¾ÌÊ"ûÄߪæþªâÚ(282Hã;ܲÍË®øùÃýب°Ï=Ǯ›ŸÊŸäâ"ª–¨Œ×ÿ¹¡k(282IÌ™¹ý¢ÞúŒ…ùÃýب°Ï=ÿ‚¾žÃ“’§õ"÷‘–ä–Œ¿¯(282GÚ´¯Ðèà £YùÃýب°Ï=˜ý˜‘¢ŒÐÀI"Ïä†÷ɯ(282IƒÈæÑ€¸µ§µùÃýب°Ï=ì‘áÒîŸÙÍá"Ÿ¡ªˆëôùÇ(282Gׇã É­ÈùÃýب°Ï=ôé‹¿¿¸ßÄ"½šòÐ䤿Œ(282HÁµÏ›é¥¸ãUùÃýب°Ï=‰±Öйˆ–Ôõ"é’¬¸ç¼‡Óª(282"§±¿Œ·¾íé„ò݃‰…Ï™sÐÙ•°‹ÁÈy(82I®‰Å„ÿ··„ò݃‰…Ï™sŒÓÜ¢¾ÌÊ"ûÄߪæþªâÚ(282H°ªåÛòÿ™˜„ò݃‰…Ï™sǮ›ŸÊŸäâ"ª–¨Œ×ÿ¹¡k(282HÖïˆÇ÷ðî’
-„ò݃‰…Ï™sÿ‚¾žÃ“’§õ"÷‘–ä–Œ¿¯(282Gæü•о°‹„ò݃‰…Ï™s˜ý˜‘¢ŒÐÀI"Ïä†÷ɯ(282HáŒêË ûÜÝ „ò݃‰…Ï™sì‘áÒîŸÙÍá"Ÿ¡ªˆëôùÇ(282Gµü­ŒºÊ¥„ò݃‰…Ï™sôé‹¿¿¸ßÄ"½šòÐ䤿Œ(282HÏææŸÞñ˜È'„ò݃‰…Ï™s‰±Öйˆ–Ôõ"é’¬¸ç¼‡Óª(282#䪧¸ëð»ÍÖ“®ß®þÏ¿ÐÙ•°‹ÁÈy(82HâÈòŸ‚Ϫ¶;“®ß®þÏ¿ŒÓÜ¢¾ÌÊ"ûÄߪæþªâÚ(282GÅöôŽåËà@“®ß®þÏ¿Ǯ›ŸÊŸäâ"ª–¨Œ×ÿ¹¡k(282H±¤ñþÜÀ«‡-“®ß®þÏ¿ÿ‚¾žÃ“’§õ"÷‘–ä–Œ¿¯(282GЇ¶­ÇéíËI“®ß®þÏ¿˜ý˜‘¢ŒÐÀI"Ïä†÷ɯ(282H¶ÛŽˆÊÜÇÔ
-“®ß®þÏ¿ì‘áÒîŸÙÍá"Ÿ¡ªˆëôùÇ(282Gñå°ì’³¯Ç“®ß®þÏ¿ôé‹¿¿¸ßÄ"½šòÐ䤿Œ(282H¥×©ë¹ÖÕÅb“®ß®þÏ¿‰±Öйˆ–Ôõ"é’¬¸ç¼‡Óª(282#¼ù´–ºîª¡Ÿ¤øÝŽ£î“KÐÙ•°‹ÁÈy(82H…üÖ½ßÇЃqŸ¤øÝŽ£î“KŒÓÜ¢¾ÌÊ"ûÄߪæþªâÚ(282GÀê÷ÅÒ×´øŸ¤øÝŽ£î“KǮ›ŸÊŸäâ"ª–¨Œ×ÿ¹¡k(282Iô ¨ø­Í¹€Ÿ¤øÝŽ£î“Kÿ‚¾žÃ“’§õ"÷‘–ä–Œ¿¯(282HÍÆýö®£ÏåËŸ¤øÝŽ£î“K˜ý˜‘¢ŒÐÀI"Ïä†÷ɯ(282H¿¾Š “ʽ៤øÝŽ£î“Kì‘áÒîŸÙÍá"Ÿ¡ªˆëôùÇ(282GºÉ¬¦“ÆçÜpŸ¤øÝŽ£î“Kôé‹¿¿¸ßÄ"½šòÐ䤿Œ(282H•úŸþî¯ø6Ÿ¤øÝŽ£î“K‰±Öйˆ–Ôõ"é’¬¸ç¼‡Óª(28:â鿨ŒÙœ®‘*:ÔØ’¯—꓌’ („:ðÿÈ€ÀíÐð© (¬:ì¹ó¢â¯¢ÚÌ (Ü :ôïÆ þ©ƒ„ø (À :õµ…çÈηŽB (¤ :¸Î½Èìù„ (:¶›èõÖð®÷m (è:¨ÆºÀõµÈï¹ (”
-:ãï©Ê½˜š¡® (¼:¥Ã¯œí…â¥w (ø
-:å½ÈÂÏò“Þó (ˆ:¶Æèܦ™¥ìß(
-(
-(
-(
-(
- B.ª ÿçû¤éåˆ!ÂŒÝëð ¢Ý›ºô¿Úó¾k2
-B"󄽾؜ߞ}™ºŽÔ–í”"žÈ¶ž•ÞŠè(
-B-âÓ»ä¾ÙÙ9!µêЊîÄa鮣öü©µ2
-B,·æúŸÌ½‚¡ûó⿼‘ÿÿƒ«ŸˆÇŽ¿¡
diff --git a/cmds/statsd/tools/dogfood/res/values/strings.xml b/cmds/statsd/tools/dogfood/res/values/strings.xml
deleted file mode 100644
index 60948a181a1b..000000000000
--- a/cmds/statsd/tools/dogfood/res/values/strings.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<resources>
-
- <string name="app_name">Statsd Dogfood</string>
-
- <string name="statsd_running">Statsd Running</string>
- <string name="statsd_not_running">Statsd NOT Running</string>
-
- <string name="push_config">Push baseline config</string>
- <string name="set_receiver">Set pendingintent</string>
- <string name="remove_receiver">Remove pendingintent</string>
-
- <string name="app_a_foreground">App A foreground</string>
- <string name="app_b_foreground">App B foreground</string>
-
-
- <string name="app_a_get_wl1">App A get wl_1</string>
- <string name="app_a_release_wl1">App A release wl_1</string>
-
- <string name="app_a_get_wl2">App A get wl_2</string>
- <string name="app_a_release_wl2">App A release wl_2</string>
-
- <string name="app_b_get_wl1">App B get wl_1</string>
- <string name="app_b_release_wl1">App B release wl_1</string>
-
- <string name="app_b_get_wl2">App B get wl_2</string>
- <string name="app_b_release_wl2">App B release wl_2</string>
-
- <string name="plug">Plug</string>
- <string name="unplug">Unplug</string>
-
- <string name="screen_on">Screen On</string>
- <string name="screen_off">Screen Off</string>
-
- <string name="custom_start">App hook start</string>
- <string name="custom_stop">App hook stop</string>
-
- <string name="dump">DumpReport</string>
- <string name="report_header">Report details</string>
-</resources>
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
deleted file mode 100644
index b6b16e40a4b2..000000000000
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.dogfood;
-
-import android.text.format.DateFormat;
-
-import com.android.os.StatsLog;
-
-import java.util.List;
-
-public class DisplayProtoUtils {
- public static void displayLogReport(StringBuilder sb, StatsLog.ConfigMetricsReportList reports) {
- sb.append("ConfigKey: ");
- if (reports.hasConfigKey()) {
- com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
- sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getId())
- .append("\n");
- }
-
- for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
- sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
- sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
- append("\n");
- sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
- append("\n");
- for (StatsLog.StatsLogReport log : report.getMetricsList()) {
- sb.append("\n\n");
- sb.append("metric id: ").append(log.getMetricId()).append("\n");
-
- switch (log.getDataCase()) {
- case DURATION_METRICS:
- sb.append("Duration metric data\n");
- displayDurationMetricData(sb, log);
- break;
- case EVENT_METRICS:
- sb.append("Event metric data\n");
- displayEventMetricData(sb, log);
- break;
- case COUNT_METRICS:
- sb.append("Count metric data\n");
- displayCountMetricData(sb, log);
- break;
- case GAUGE_METRICS:
- sb.append("Gauge metric data\n");
- displayGaugeMetricData(sb, log);
- break;
- case VALUE_METRICS:
- sb.append("Value metric data\n");
- displayValueMetricData(sb, log);
- break;
- case DATA_NOT_SET:
- sb.append("No metric data\n");
- break;
- }
- }
- }
- }
-
- public static String getDateStr(long nanoSec) {
- return DateFormat.format("dd/MM hh:mm:ss", nanoSec/1000000).toString();
- }
-
- private static void displayDimension(StringBuilder sb, StatsLog.DimensionsValue dimensionValue) {
- sb.append(dimensionValue.getField()).append(":");
- if (dimensionValue.hasValueBool()) {
- sb.append(dimensionValue.getValueBool());
- } else if (dimensionValue.hasValueFloat()) {
- sb.append(dimensionValue.getValueFloat());
- } else if (dimensionValue.hasValueInt()) {
- sb.append(dimensionValue.getValueInt());
- } else if (dimensionValue.hasValueStr()) {
- sb.append(dimensionValue.getValueStr());
- } else if (dimensionValue.hasValueTuple()) {
- sb.append("{");
- for (StatsLog.DimensionsValue child :
- dimensionValue.getValueTuple().getDimensionsValueList()) {
- displayDimension(sb, child);
- }
- sb.append("}");
- }
- sb.append(" ");
- }
-
- public static void displayDurationMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- StatsLog.StatsLogReport.DurationMetricDataWrapper durationMetricDataWrapper
- = log.getDurationMetrics();
- sb.append("Dimension size: ").append(durationMetricDataWrapper.getDataCount()).append("\n");
- for (StatsLog.DurationMetricData duration : durationMetricDataWrapper.getDataList()) {
- sb.append("dimension_in_what: ");
- displayDimension(sb, duration.getDimensionsInWhat());
- sb.append("\n");
- if (duration.hasDimensionsInCondition()) {
- sb.append("dimension_in_condition: ");
- displayDimension(sb, duration.getDimensionsInCondition());
- sb.append("\n");
- }
-
- for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
- .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
- .append(info.getDurationNanos()).append(" ns\n");
- }
- }
- }
-
- public static void displayEventMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Contains ").append(log.getEventMetrics().getDataCount()).append(" events\n");
- StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
- log.getEventMetrics();
- for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
- sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
- sb.append(event.getAtom().getPushedCase().toString()).append("\n");
- }
- }
-
- public static void displayCountMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- StatsLog.StatsLogReport.CountMetricDataWrapper countMetricDataWrapper
- = log.getCountMetrics();
- sb.append("Dimension size: ").append(countMetricDataWrapper.getDataCount()).append("\n");
- for (StatsLog.CountMetricData count : countMetricDataWrapper.getDataList()) {
- sb.append("dimension_in_what: ");
- displayDimension(sb, count.getDimensionsInWhat());
- sb.append("\n");
- if (count.hasDimensionsInCondition()) {
- sb.append("dimension_in_condition: ");
- displayDimension(sb, count.getDimensionsInCondition());
- sb.append("\n");
- }
-
- for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
- .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
- .append(info.getCount()).append("\n");
- }
- }
- }
-
- public static void displayGaugeMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Display me!");
- }
-
- public static void displayValueMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Display me!");
- }
-}
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
deleted file mode 100644
index 4f4dd011e419..000000000000
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.dogfood;
-
-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;
-import android.os.Bundle;
-import android.util.Log;
-import android.util.StatsLog;
-import android.view.View;
-import android.widget.TextView;
-import android.widget.Toast;
-import android.os.IStatsManager;
-import android.os.ServiceManager;
-
-import java.io.InputStream;
-
-import static com.android.statsd.dogfood.DisplayProtoUtils.displayLogReport;
-
-public class MainActivity extends Activity {
- private final static String TAG = "StatsdDogfood";
- private final static long CONFIG_ID = 987654321;
-
- final int[] mUids = {11111111, 2222222};
- StatsManager mStatsManager;
- TextView mReportText;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_main);
-
- findViewById(R.id.app_a_wake_lock_acquire1).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockAcquire(0, "wl_1");
- }
- });
-
- findViewById(R.id.app_b_wake_lock_acquire1).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockAcquire(1, "wl_1");
- }
- });
-
- findViewById(R.id.app_a_wake_lock_acquire2).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockAcquire(0, "wl_2");
- }
- });
-
- findViewById(R.id.app_b_wake_lock_acquire2).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockAcquire(1, "wl_2");
- }
- });
-
- findViewById(R.id.app_a_wake_lock_release1).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockRelease(0, "wl_1");
- }
- });
-
-
- findViewById(R.id.app_b_wake_lock_release1).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockRelease(1, "wl_1");
- }
- });
-
- findViewById(R.id.app_a_wake_lock_release2).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockRelease(0, "wl_2");
- }
- });
-
-
- findViewById(R.id.app_b_wake_lock_release2).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockRelease(1, "wl_2");
- }
- });
-
-
- findViewById(R.id.plug).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED,
- StatsLog.PLUGGED_STATE_CHANGED__STATE__BATTERY_PLUGGED_AC);
- }
- });
-
- findViewById(R.id.unplug).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED,
- StatsLog.PLUGGED_STATE_CHANGED__STATE__BATTERY_PLUGGED_NONE);
- }
- });
-
- findViewById(R.id.screen_on).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
- StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON);
- }
- });
-
- findViewById(R.id.screen_off).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
- StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF);
- }
- });
-
- findViewById(R.id.custom_start).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.logStart(8);
- }
- });
-
- findViewById(R.id.custom_stop).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.logStop(8);
- }
- });
-
- mReportText = (TextView) findViewById(R.id.report_text);
-
- findViewById(R.id.dump).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (!statsdRunning()) {
- return;
- }
- if (mStatsManager != null) {
- 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!");
- }
- }
- });
-
- findViewById(R.id.push_config).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- try {
- if (!statsdRunning()) {
- return;
- }
- Resources res = getResources();
- InputStream inputStream = res.openRawResource(R.raw.statsd_baseline_config);
-
- byte[] config = new byte[inputStream.available()];
- inputStream.read(config);
- if (mStatsManager != null) {
- try {
- mStatsManager.addConfig(CONFIG_ID, config);
- Toast.makeText(
- MainActivity.this, "Config pushed", Toast.LENGTH_LONG).show();
- } catch (StatsUnavailableException | IllegalArgumentException e) {
- Toast.makeText(MainActivity.this, "Config push FAILED!",
- Toast.LENGTH_LONG).show();
- }
- }
- } catch (Exception e) {
- Toast.makeText(MainActivity.this, "failed to read config", Toast.LENGTH_LONG);
- }
- }
- });
-
- PendingIntent pi = PendingIntent.getService(this, 0,
- new Intent(this, ReceiverIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
- findViewById(R.id.set_receiver).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- try {
- if (!statsdRunning()) {
- return;
- }
- if (mStatsManager != null) {
- try {
- mStatsManager.setFetchReportsOperation(pi, CONFIG_ID);
- Toast.makeText(MainActivity.this,
- "Receiver specified to pending intent", Toast.LENGTH_LONG)
- .show();
- } catch (StatsUnavailableException e) {
- Toast.makeText(MainActivity.this, "Statsd did not set receiver",
- Toast.LENGTH_LONG)
- .show();
- }
- }
- } catch (Exception e) {
- Toast.makeText(MainActivity.this, "failed to set receiver", Toast.LENGTH_LONG);
- }
- }
- });
- findViewById(R.id.remove_receiver).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- try {
- if (!statsdRunning()) {
- return;
- }
- if (mStatsManager != null) {
- try {
- mStatsManager.setFetchReportsOperation(null, CONFIG_ID);
- Toast.makeText(MainActivity.this, "Receiver remove", Toast.LENGTH_LONG)
- .show();
- } catch (StatsUnavailableException e) {
- Toast.makeText(MainActivity.this, "Statsd did not remove receiver",
- Toast.LENGTH_LONG)
- .show();
- }
- }
- } catch (Exception e) {
- Toast.makeText(
- MainActivity.this, "failed to remove receiver", Toast.LENGTH_LONG);
- }
- }
- });
- mStatsManager = (StatsManager) getSystemService("stats");
- }
-
- private boolean statsdRunning() {
- if (IStatsManager.Stub.asInterface(ServiceManager.getService("stats")) == null) {
- Log.d(TAG, "Statsd not running");
- Toast.makeText(MainActivity.this, "Statsd NOT running!", Toast.LENGTH_LONG).show();
- return false;
- }
- return true;
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- Log.d(TAG, "new intent: " + intent.getIntExtra("pkg", 0));
- int pkg = intent.getIntExtra("pkg", 0);
- String name = intent.getStringExtra("name");
- if (intent.hasExtra("acquire")) {
- onWakeLockAcquire(pkg, name);
- } else if (intent.hasExtra("release")) {
- onWakeLockRelease(pkg, name);
- }
- }
-
- private void displayData(byte[] data) {
- com.android.os.StatsLog.ConfigMetricsReportList reports = null;
- boolean good = false;
- if (data != null) {
- try {
- reports = com.android.os.StatsLog.ConfigMetricsReportList.parseFrom(data);
- good = true;
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- // display it in the text view.
- }
- }
- int size = data == null ? 0 : data.length;
- StringBuilder sb = new StringBuilder();
- sb.append(good ? "Proto parsing OK!" : "Proto parsing Error!");
- sb.append(" size:").append(size).append("\n");
-
- if (good && reports != null) {
- displayLogReport(sb, reports);
- mReportText.setText(sb.toString());
- }
- }
-
-
- private void onWakeLockAcquire(int id, String name) {
- if (id > 1) {
- Log.d(TAG, "invalid pkg id");
- return;
- }
- int[] uids = new int[]{mUids[id]};
- String[] tags = new String[]{"acquire"};
- StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
- StatsLog.WAKELOCK_STATE_CHANGED__TYPE__PARTIAL_WAKE_LOCK, name,
- StatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
- StringBuilder sb = new StringBuilder();
- sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0)
- .append(", ").append(name).append(", 1);");
- Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
- }
-
- private void onWakeLockRelease(int id, String name) {
- if (id > 1) {
- Log.d(TAG, "invalid pkg id");
- return;
- }
- int[] uids = new int[]{mUids[id]};
- String[] tags = new String[]{"release"};
- StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
- StatsLog.WAKELOCK_STATE_CHANGED__TYPE__PARTIAL_WAKE_LOCK, name,
- StatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
- StringBuilder sb = new StringBuilder();
- sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0)
- .append(", ").append(name).append(", 0);");
- Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
- }
-
- public static class ReceiverIntentService extends IntentService {
- public ReceiverIntentService() {
- super("ReceiverIntentService");
- }
-
- /**
- * The IntentService calls this method from the default worker thread with
- * the intent that started the service. When this method returns, IntentService
- * stops the service, as appropriate.
- */
- @Override
- protected void onHandleIntent(Intent intent) {
- Log.i(TAG, "Received notification that we should call getData");
- }
- }
-}
diff --git a/cmds/statsd/tools/loadtest/Android.bp b/cmds/statsd/tools/loadtest/Android.bp
deleted file mode 100644
index bf87fc51dce1..000000000000
--- a/cmds/statsd/tools/loadtest/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2017 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.
-//
-//
-
-android_app {
- name: "StatsdLoadtest",
- platform_apis: true,
-
- srcs: ["src/**/*.java"],
-
- resource_dirs: ["res"],
- static_libs: [
- "platformprotoslite",
- "statsdprotolite",
- ],
-
- certificate: "platform",
- privileged: true,
- dex_preopt: {
- enabled: false,
- },
- optimize: {
- enabled: false,
- },
-}
diff --git a/cmds/statsd/tools/loadtest/AndroidManifest.xml b/cmds/statsd/tools/loadtest/AndroidManifest.xml
deleted file mode 100644
index 2bf8ca95d846..000000000000
--- a/cmds/statsd/tools/loadtest/AndroidManifest.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.statsd.loadtest"
- android:sharedUserId="android.uid.system"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-permission android:name="android.permission.DUMP" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <activity
- android:name=".LoadtestActivity"
- android:label="@string/app_name"
- android:launchMode="singleTop" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <receiver android:name=".LoadtestActivity$PusherAlarmReceiver" />
- <receiver android:name=".LoadtestActivity$StopperAlarmReceiver"/>
- <receiver android:name=".PerfData$PerfAlarmReceiver"/>
- </application>
-</manifest>
diff --git a/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 55621cc1074f..000000000000
--- a/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 11ec2068be19..000000000000
--- a/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 7c02b784aa5d..000000000000
--- a/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 915d91441349..000000000000
--- a/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml b/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
deleted file mode 100644
index d6f804734385..000000000000
--- a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
+++ /dev/null
@@ -1,208 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <LinearLayout
- android:id="@+id/outside"
- android:clickable="true"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginRight="10dp"
- android:layout_marginLeft="10dp"
- android:orientation="vertical">
- <requestFocus />
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <TextView
- android:textSize="30dp"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/replication_label" />
- <EditText
- android:id="@+id/replication"
- android:inputType="number"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLength="4"
- android:text="@integer/replication_default"
- android:textSize="30dp"/>
- </LinearLayout>
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <TextView
- android:textSize="30dp"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/bucket_label" />
- <Spinner
- android:id="@+id/bucket_spinner"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:prompt="@string/bucket_label"/>
- </LinearLayout>
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <TextView
- android:textSize="30dp"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/period_label" />
- <EditText
- android:id="@+id/period"
- android:inputType="number"
- android:layout_weight="1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:maxLength="3"
- android:text="@integer/period_default"
- android:textSize="30dp"/>
- </LinearLayout>
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <TextView
- android:textSize="30dp"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/burst_label" />
- <EditText
- android:id="@+id/burst"
- android:inputType="number"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLength="4"
- android:text="@integer/burst_default"
- android:textSize="30dp"/>
- </LinearLayout>
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <TextView
- android:textSize="30dp"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/duration_label" />
- <EditText
- android:id="@+id/duration"
- android:inputType="number"
- android:layout_weight="1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:maxLength="4"
- android:text="@integer/duration_default"
- android:textSize="30dp"/>
- </LinearLayout>
- <CheckBox
- android:id="@+id/placebo"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/placebo"
- android:checked="false" />
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <CheckBox
- android:id="@+id/include_count"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/count"
- android:checked="true"/>
- <CheckBox
- android:id="@+id/include_duration"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/duration"
- android:checked="true"/>
- <CheckBox
- android:id="@+id/include_event"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/event"
- android:checked="true"/>
- <CheckBox
- android:id="@+id/include_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/value"
- android:checked="true"/>
- <CheckBox
- android:id="@+id/include_gauge"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/gauge"
- android:checked="true"/>
- </LinearLayout>
-
- <Space
- android:layout_width="1dp"
- android:layout_height="30dp"/>
-
- <Button
- android:id="@+id/start_stop"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="#ffff0000"
- android:text="@string/start"
- android:textSize="50dp"/>
-
- <Space
- android:layout_width="1dp"
- android:layout_height="30dp"/>
-
- <Space
- android:layout_width="1dp"
- android:layout_height="30dp"/>
-
- <TextView
- android:id="@+id/report_text"
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
-</ScrollView>
diff --git a/cmds/statsd/tools/loadtest/res/layout/spinner_item.xml b/cmds/statsd/tools/loadtest/res/layout/spinner_item.xml
deleted file mode 100644
index b03da06f7a77..000000000000
--- a/cmds/statsd/tools/loadtest/res/layout/spinner_item.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="30dp"
- android:gravity="left"
- android:padding="5dip"
- />
diff --git a/cmds/statsd/tools/loadtest/res/raw/loadtest_config b/cmds/statsd/tools/loadtest/res/raw/loadtest_config
deleted file mode 100755
index 24221908cbeb..000000000000
--- a/cmds/statsd/tools/loadtest/res/raw/loadtest_config
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/values/integers.xml b/cmds/statsd/tools/loadtest/res/values/integers.xml
deleted file mode 100644
index c2407d3b85f2..000000000000
--- a/cmds/statsd/tools/loadtest/res/values/integers.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<resources>
- <integer name="burst_default">1</integer>
- <integer name="period_default">2</integer>
- <integer name="replication_default">1</integer>
- <integer name="duration_default">240</integer>
-</resources>
diff --git a/cmds/statsd/tools/loadtest/res/values/strings.xml b/cmds/statsd/tools/loadtest/res/values/strings.xml
deleted file mode 100644
index e8ae3f82a7e3..000000000000
--- a/cmds/statsd/tools/loadtest/res/values/strings.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<resources>
- <string name="app_name">Statsd Loadtest</string>
- <string name="bucket_label">bucket size (mins):&#160;</string>
- <string name="burst_label">burst:&#160;</string>
- <string name="bucket_default">FIVE_MINUTES</string>
- <string name="placebo">placebo</string>
- <string name="period_label">logging period (secs):&#160;</string>
- <string name="replication_label">metric replication:&#160;</string>
- <string name="duration_label">test duration (mins):&#160;</string>
- <string name="start"> &#160;Start&#160; </string>
- <string name="stop"> &#160;Stop&#160; </string>
- <string name="count"> count </string>
- <string name="duration"> duration </string>
- <string name="event"> event </string>
- <string name="value"> value </string>
- <string name="gauge"> gauge </string>
-
-</resources>
diff --git a/cmds/statsd/tools/loadtest/run_loadtest.sh b/cmds/statsd/tools/loadtest/run_loadtest.sh
deleted file mode 100755
index 3c93a0613183..000000000000
--- a/cmds/statsd/tools/loadtest/run_loadtest.sh
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/bin/sh
-#
-# Script that measures statsd's PSS under an increasing number of metrics.
-
-# Globals.
-pss=""
-pid=""
-
-# Starts the loadtest.
-start_loadtest() {
- echo "Starting loadtest"
- adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "start"
-}
-
-# Stops the loadtest.
-stop_loadtest() {
- echo "Stopping loadtest"
- adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "stop"
-}
-
-# Sets the metrics replication.
-# Arguments:
-# $1: The replication factor.
-set_replication() {
- adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "set_replication" --ei "replication" "${1}"
- echo "Replication set to ${1}"
-}
-
-# Reads statsd's pid and PSS.
-update_pid_and_pss() {
- # Command that reads the PSS for statsd. This also gives us its pid.
- get_mem=$(adb shell dumpsys meminfo |grep statsd)
- # Looks for statsd's pid.
- regex="([0-9,]+)K: statsd \(pid ([0-9]+)\).*"
- if [[ $get_mem =~ $regex ]]; then
- pss=$(echo "${BASH_REMATCH[1]}" | tr -d , | sed 's/\.//g')
- pid=$(echo "${BASH_REMATCH[2]}")
- else
- echo $cmd doesnt match $regex
- fi
-}
-
-# Kills statsd.
-# Assumes the pid has been set.
-kill_statsd() {
- echo "Killing statsd (pid ${pid})"
- adb shell kill -9 "${pid}"
-}
-
-# Main loop.
-main() {
- start_time=$(date +%s)
- values=()
- stop_loadtest
-
- echo ""
- echo "********************* NEW LOADTEST ************************"
- update_pid_and_pss
- for replication in 1 2 4 8 16 32 64 128 256 512 1024 2048 4096
- do
- echo "**** Starting test at replication ${replication} ****"
-
- # (1) Restart statsd. This will ensure its state is empty.
- kill_statsd
- sleep 3 # wait a bit for it to restart
- update_pid_and_pss
- echo "Before the test, statsd's PSS is ${pss}"
-
- # (2) Set the replication.
- set_replication "${replication}"
- sleep 1 # wait a bit
-
- # (3) Start the loadtest.
- start_loadtest
-
- # (4) Wait several seconds, then read the PSS.
- sleep 100 && update_pid_and_pss
- echo "During the test, statsd's PSS is ${pss}"
- values+=(${pss})
-
- echo "Values: ${values[@]}"
-
- # (5) Stop loadtest.
- stop_loadtest
- sleep 2
-
- echo ""
- done
-
- end_time=$(date +%s)
- echo "Completed loadtest in $((${end_time} - ${start_time})) seconds."
-
- values_as_str=$(IFS=$'\n'; echo "${values[*]}")
- echo "The PSS values are:"
- echo "${values_as_str}"
- echo ""
-}
-
-main
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java
deleted file mode 100644
index bab0c1e3f540..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.util.Log;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import java.text.ParseException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class BatteryDataRecorder extends PerfDataRecorder {
- private static final String TAG = "loadtest.BatteryDataRecorder";
- private static final String DUMP_FILENAME = TAG + "_dump.tmp";
-
- public BatteryDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
- int burst, boolean includeCountMetric, boolean includeDurationMetric,
- boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
- super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
- includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
- }
-
- @Override
- public void startRecording(Context context) {
- // Reset batterystats.
- runDumpsysStats(context, DUMP_FILENAME, "batterystats", "--reset");
- }
-
- @Override
- public void onAlarm(Context context) {
- // Nothing to do as for battery, the whole data is in the final dumpsys call.
- }
-
- @Override
- public void stopRecording(Context context) {
- StringBuilder sb = new StringBuilder();
- // Don't use --checkin.
- runDumpsysStats(context, DUMP_FILENAME, "batterystats");
- readDumpData(context, DUMP_FILENAME, new BatteryStatsParser(), sb);
- writeData(context, "battery_", "time,battery_level", sb);
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
deleted file mode 100644
index 203d97acefd8..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.util.Log;
-import java.text.ParseException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class BatteryStatsParser implements PerfParser {
-
- private static final Pattern LINE_PATTERN =
- Pattern.compile("\\s*\\+*(\\S*)\\s\\(\\d+\\)\\s(\\d\\d\\d)\\s.*");
- private static final Pattern TIME_PATTERN =
- Pattern.compile("(\\d+)?(h)?(\\d+)?(m)?(\\d+)?(s)?(\\d+)?(ms)?");
- private static final String TAG = "loadtest.BatteryStatsParser";
-
- private boolean mHistoryStarted;
- private boolean mHistoryEnded;
-
- public BatteryStatsParser() {
- }
-
- @Override
- @Nullable
- public String parseLine(String line) {
- if (mHistoryEnded) {
- return null;
- }
- if (!mHistoryStarted) {
- if (line.contains("Battery History")) {
- mHistoryStarted = true;
- }
- return null;
- }
- if (line.isEmpty()) {
- mHistoryEnded = true;
- return null;
- }
- Matcher lineMatcher = LINE_PATTERN.matcher(line);
- if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
- if (lineMatcher.group(1).equals("0")) {
- return "0," + lineMatcher.group(2) + "\n";
- } else {
- Matcher timeMatcher = TIME_PATTERN.matcher(lineMatcher.group(1));
- if (timeMatcher.find()) {
- Long time = getTime(lineMatcher.group(1));
- if (time != null) {
- return time + "," + lineMatcher.group(2) + "\n";
- } else {
- return null; // bad time
- }
- } else {
- return null; // bad or no time
- }
- }
- }
- return null;
- }
-
- @Nullable
- private Long getTime(String group) {
- if ("0".equals(group)) {
- return 0L;
- }
- Matcher timeMatcher = TIME_PATTERN.matcher(group);
- if (!timeMatcher.find()) {
- return null;
- }
-
- // Get rid of "ms".
- String[] matches = group.split("ms", -1);
- if (matches.length > 1) {
- group = matches[0];
- }
-
- long time = 0L;
- matches = group.split("h");
- if (matches.length > 1) {
- time += Long.parseLong(matches[0]) * 60 * 60 * 1000; // hours
- group = matches[1];
- }
- matches = group.split("m");
- if (matches.length > 1) {
- time += Long.parseLong(matches[0]) * 60 * 1000; // minutes
- group = matches[1];
- }
- matches = group.split("s");
- if (matches.length > 1) {
- time += Long.parseLong(matches[0]) * 1000; // seconds
- group = matches[1];
- }
-
- if (!group.isEmpty()) {
- time += Long.parseLong(group); // milliseconds
- }
- return time;
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
deleted file mode 100644
index 2e0161be8096..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-import com.android.internal.os.StatsdConfigProto.Predicate;
-import com.android.internal.os.StatsdConfigProto.CountMetric;
-import com.android.internal.os.StatsdConfigProto.DurationMetric;
-import com.android.internal.os.StatsdConfigProto.MetricConditionLink;
-import com.android.internal.os.StatsdConfigProto.EventMetric;
-import com.android.internal.os.StatsdConfigProto.GaugeMetric;
-import com.android.internal.os.StatsdConfigProto.ValueMetric;
-import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
-import com.android.internal.os.StatsdConfigProto.AtomMatcher;
-import com.android.internal.os.StatsdConfigProto.SimplePredicate;
-import com.android.internal.os.StatsdConfigProto.StatsdConfig;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Creates StatsdConfig protos for loadtesting.
- */
-public class ConfigFactory {
- public static class ConfigMetadata {
- public final byte[] bytes;
- public final int numMetrics;
-
- public ConfigMetadata(byte[] bytes, int numMetrics) {
- this.bytes = bytes;
- this.numMetrics = numMetrics;
- }
- }
-
- public static final long CONFIG_ID = 123456789;
-
- private static final String TAG = "loadtest.ConfigFactory";
-
- private final StatsdConfig mTemplate;
-
- public ConfigFactory(Context context) {
- // Read the config template from the resoures.
- Resources res = context.getResources();
- byte[] template = null;
- StatsdConfig templateProto = null;
- try {
- InputStream inputStream = res.openRawResource(R.raw.loadtest_config);
- template = new byte[inputStream.available()];
- inputStream.read(template);
- templateProto = StatsdConfig.parseFrom(template);
- } catch (IOException e) {
- Log.e(TAG, "Unable to read or parse loadtest config template. Using an empty config.");
- }
- mTemplate = templateProto == null ? StatsdConfig.newBuilder().build() : templateProto;
-
- Log.d(TAG, "Loadtest template config: " + mTemplate);
- }
-
- /**
- * Generates a config.
- *
- * All configs are based on the same template.
- * That template is designed to make the most use of the set of atoms that {@code SequencePusher}
- * pushes, and to exercise as many of the metrics features as possible.
- * Furthermore, by passing a replication factor to this method, one can artificially inflate
- * the number of metrics in the config. One can also adjust the bucket size for aggregate
- * metrics.
- *
- * @param replication The number of times each metric is replicated in the config.
- * If the config template has n metrics, the generated config will have n * replication
- * ones
- * @param bucketMillis The bucket size, in milliseconds, for aggregate metrics
- * @param placebo If true, only return an empty config
- * @return The serialized config and the number of metrics.
- */
- public ConfigMetadata getConfig(int replication, TimeUnit bucket, boolean placebo,
- boolean includeCount, boolean includeDuration, boolean includeEvent,
- boolean includeValue, boolean includeGauge) {
- StatsdConfig.Builder config = StatsdConfig.newBuilder()
- .setId(CONFIG_ID);
- if (placebo) {
- replication = 0; // Config will be empty, aside from a name.
- }
- int numMetrics = 0;
- for (int i = 0; i < replication; i++) {
- // metrics
- if (includeEvent) {
- for (EventMetric metric : mTemplate.getEventMetricList()) {
- addEventMetric(metric, i, config);
- numMetrics++;
- }
- }
- if (includeCount) {
- for (CountMetric metric : mTemplate.getCountMetricList()) {
- addCountMetric(metric, i, bucket, config);
- numMetrics++;
- }
- }
- if (includeDuration) {
- for (DurationMetric metric : mTemplate.getDurationMetricList()) {
- addDurationMetric(metric, i, bucket, config);
- numMetrics++;
- }
- }
- if (includeGauge) {
- for (GaugeMetric metric : mTemplate.getGaugeMetricList()) {
- addGaugeMetric(metric, i, bucket, config);
- numMetrics++;
- }
- }
- if (includeValue) {
- for (ValueMetric metric : mTemplate.getValueMetricList()) {
- addValueMetric(metric, i, bucket, config);
- numMetrics++;
- }
- }
- // predicates
- for (Predicate predicate : mTemplate.getPredicateList()) {
- addPredicate(predicate, i, config);
- }
- // matchers
- for (AtomMatcher matcher : mTemplate.getAtomMatcherList()) {
- addMatcher(matcher, i, config);
- }
- }
-
- Log.d(TAG, "Loadtest config is : " + config.build());
- Log.d(TAG, "Generated config has " + numMetrics + " metrics");
-
- return new ConfigMetadata(config.build().toByteArray(), numMetrics);
- }
-
- /**
- * Creates {@link MetricConditionLink}s that are identical to the one passed to this method,
- * except that the names are appended with the provided suffix.
- */
- private List<MetricConditionLink> getLinks(
- List<MetricConditionLink> links, int suffix) {
- List<MetricConditionLink> newLinks = new ArrayList();
- for (MetricConditionLink link : links) {
- newLinks.add(link.toBuilder()
- .setCondition(link.getCondition() + suffix)
- .build());
- }
- return newLinks;
- }
-
- /**
- * Creates an {@link EventMetric} based on the template. Makes sure that all names are appended
- * with the provided suffix. Then adds that metric to the config.
- */
- private void addEventMetric(EventMetric template, int suffix, StatsdConfig.Builder config) {
- EventMetric.Builder metric = template.toBuilder()
- .setId(template.getId() + suffix)
- .setWhat(template.getWhat() + suffix);
- if (template.hasCondition()) {
- metric.setCondition(template.getCondition() + suffix);
- }
- if (template.getLinksCount() > 0) {
- List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
- metric.clearLinks();
- metric.addAllLinks(links);
- }
- config.addEventMetric(metric);
- }
-
- /**
- * Creates a {@link CountMetric} based on the template. Makes sure that all names are appended
- * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
- */
- private void addCountMetric(CountMetric template, int suffix, TimeUnit bucket,
- StatsdConfig.Builder config) {
- CountMetric.Builder metric = template.toBuilder()
- .setId(template.getId() + suffix)
- .setWhat(template.getWhat() + suffix);
- if (template.hasCondition()) {
- metric.setCondition(template.getCondition() + suffix);
- }
- if (template.getLinksCount() > 0) {
- List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
- metric.clearLinks();
- metric.addAllLinks(links);
- }
- metric.setBucket(bucket);
- config.addCountMetric(metric);
- }
-
- /**
- * Creates a {@link DurationMetric} based on the template. Makes sure that all names are appended
- * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
- */
- private void addDurationMetric(DurationMetric template, int suffix, TimeUnit bucket,
- StatsdConfig.Builder config) {
- DurationMetric.Builder metric = template.toBuilder()
- .setId(template.getId() + suffix)
- .setWhat(template.getWhat() + suffix);
- if (template.hasCondition()) {
- metric.setCondition(template.getCondition() + suffix);
- }
- if (template.getLinksCount() > 0) {
- List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
- metric.clearLinks();
- metric.addAllLinks(links);
- }
- metric.setBucket(bucket);
- config.addDurationMetric(metric);
- }
-
- /**
- * Creates a {@link GaugeMetric} based on the template. Makes sure that all names are appended
- * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
- */
- private void addGaugeMetric(GaugeMetric template, int suffix, TimeUnit bucket,
- StatsdConfig.Builder config) {
- GaugeMetric.Builder metric = template.toBuilder()
- .setId(template.getId() + suffix)
- .setWhat(template.getWhat() + suffix);
- if (template.hasCondition()) {
- metric.setCondition(template.getCondition() + suffix);
- }
- if (template.getLinksCount() > 0) {
- List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
- metric.clearLinks();
- metric.addAllLinks(links);
- }
- metric.setBucket(bucket);
- config.addGaugeMetric(metric);
- }
-
- /**
- * Creates a {@link ValueMetric} based on the template. Makes sure that all names are appended
- * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
- */
- private void addValueMetric(ValueMetric template, int suffix, TimeUnit bucket,
- StatsdConfig.Builder config) {
- ValueMetric.Builder metric = template.toBuilder()
- .setId(template.getId() + suffix)
- .setWhat(template.getWhat() + suffix);
- if (template.hasCondition()) {
- metric.setCondition(template.getCondition() + suffix);
- }
- if (template.getLinksCount() > 0) {
- List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
- metric.clearLinks();
- metric.addAllLinks(links);
- }
- metric.setBucket(bucket);
- config.addValueMetric(metric);
- }
-
- /**
- * Creates a {@link Predicate} based on the template. Makes sure that all names
- * are appended with the provided suffix. Then adds that predicate to the config.
- */
- private void addPredicate(Predicate template, int suffix, StatsdConfig.Builder config) {
- Predicate.Builder predicate = template.toBuilder()
- .setId(template.getId() + suffix);
- if (template.hasCombination()) {
- Predicate.Combination.Builder cb = template.getCombination().toBuilder()
- .clearPredicate();
- for (long child : template.getCombination().getPredicateList()) {
- cb.addPredicate(child + suffix);
- }
- predicate.setCombination(cb.build());
- }
- if (template.hasSimplePredicate()) {
- SimplePredicate.Builder sc = template.getSimplePredicate().toBuilder()
- .setStart(template.getSimplePredicate().getStart() + suffix)
- .setStop(template.getSimplePredicate().getStop() + suffix);
- if (template.getSimplePredicate().hasStopAll()) {
- sc.setStopAll(template.getSimplePredicate().getStopAll() + suffix);
- }
- predicate.setSimplePredicate(sc.build());
- }
- config.addPredicate(predicate);
- }
-
- /**
- * Creates a {@link AtomMatcher} based on the template. Makes sure that all names
- * are appended with the provided suffix. Then adds that matcher to the config.
- */
- private void addMatcher(AtomMatcher template, int suffix, StatsdConfig.Builder config) {
- AtomMatcher.Builder matcher = template.toBuilder()
- .setId(template.getId() + suffix);
- if (template.hasCombination()) {
- AtomMatcher.Combination.Builder cb = template.getCombination().toBuilder()
- .clearMatcher();
- for (long child : template.getCombination().getMatcherList()) {
- cb.addMatcher(child + suffix);
- }
- matcher.setCombination(cb);
- }
- config.addAtomMatcher(matcher);
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
deleted file mode 100644
index d55f3f31fd9f..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.text.format.DateFormat;
-
-import com.android.os.StatsLog;
-
-import java.util.List;
-
-public class DisplayProtoUtils {
- private static final int MAX_NUM_METRICS_TO_DISPLAY = 10;
-
- public static void displayLogReport(StringBuilder sb, StatsLog.ConfigMetricsReportList reports) {
- sb.append("******************** Report ********************\n");
- if (reports.hasConfigKey()) {
- sb.append("ConfigKey: ");
- com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
- sb.append("\tuid: ").append(key.getUid()).append(" id: ").append(key.getId())
- .append("\n");
- }
-
- int numMetrics = 0;
- for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
- sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
- sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
- append("\n");
- sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
- append("\n");
- for (StatsLog.StatsLogReport log : report.getMetricsList()) {
- numMetrics++;
- if (numMetrics > MAX_NUM_METRICS_TO_DISPLAY) {
- sb.append("... output truncated\n");
- sb.append("************************************************");
- return;
- }
- sb.append("\n");
- sb.append("metric id: ").append(log.getMetricId()).append("\n");
-
- switch (log.getDataCase()) {
- case DURATION_METRICS:
- sb.append("Duration metric data\n");
- displayDurationMetricData(sb, log);
- break;
- case EVENT_METRICS:
- sb.append("Event metric data\n");
- displayEventMetricData(sb, log);
- break;
- case COUNT_METRICS:
- sb.append("Count metric data\n");
- displayCountMetricData(sb, log);
- break;
- case GAUGE_METRICS:
- sb.append("Gauge metric data\n");
- displayGaugeMetricData(sb, log);
- break;
- case VALUE_METRICS:
- sb.append("Value metric data\n");
- displayValueMetricData(sb, log);
- break;
- case DATA_NOT_SET:
- sb.append("No metric data\n");
- break;
- }
- }
- }
- sb.append("************************************************");
- }
-
- public static String getDateStr(long nanoSec) {
- return DateFormat.format("dd/MM hh:mm:ss", nanoSec/1000000).toString();
- }
-
- private static void displayDimension(StringBuilder sb, StatsLog.DimensionsValue dimensionValue) {
- sb.append(dimensionValue.getField()).append(":");
- if (dimensionValue.hasValueBool()) {
- sb.append(dimensionValue.getValueBool());
- } else if (dimensionValue.hasValueFloat()) {
- sb.append(dimensionValue.getValueFloat());
- } else if (dimensionValue.hasValueInt()) {
- sb.append(dimensionValue.getValueInt());
- } else if (dimensionValue.hasValueStr()) {
- sb.append(dimensionValue.getValueStr());
- } else if (dimensionValue.hasValueTuple()) {
- sb.append("{");
- for (StatsLog.DimensionsValue child :
- dimensionValue.getValueTuple().getDimensionsValueList()) {
- displayDimension(sb, child);
- }
- sb.append("}");
- }
- sb.append(" ");
- }
-
- public static void displayDurationMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- StatsLog.StatsLogReport.DurationMetricDataWrapper durationMetricDataWrapper
- = log.getDurationMetrics();
- sb.append("Dimension size: ").append(durationMetricDataWrapper.getDataCount()).append("\n");
- for (StatsLog.DurationMetricData duration : durationMetricDataWrapper.getDataList()) {
- sb.append("dimension_in_what: ");
- displayDimension(sb, duration.getDimensionsInWhat());
- sb.append("\n");
- if (duration.hasDimensionsInCondition()) {
- sb.append("dimension_in_condition: ");
- displayDimension(sb, duration.getDimensionsInCondition());
- sb.append("\n");
- }
-
- for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
- .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
- .append(info.getDurationNanos()).append(" ns\n");
- }
- }
- }
-
- public static void displayEventMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Contains ").append(log.getEventMetrics().getDataCount()).append(" events\n");
- StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
- log.getEventMetrics();
- for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
- sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
- sb.append(event.getAtom().getPushedCase().toString()).append("\n");
- }
- }
-
- public static void displayCountMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- StatsLog.StatsLogReport.CountMetricDataWrapper countMetricDataWrapper
- = log.getCountMetrics();
- sb.append("Dimension size: ").append(countMetricDataWrapper.getDataCount()).append("\n");
- for (StatsLog.CountMetricData count : countMetricDataWrapper.getDataList()) {
- sb.append("dimension_in_what: ");
- displayDimension(sb, count.getDimensionsInWhat());
- sb.append("\n");
- if (count.hasDimensionsInCondition()) {
- sb.append("dimension_in_condition: ");
- displayDimension(sb, count.getDimensionsInCondition());
- sb.append("\n");
- }
-
- for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
- .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
- .append(info.getCount()).append("\n");
- }
- }
- }
-
- public static void displayGaugeMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Display me!");
- }
-
- public static void displayValueMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Display me!");
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
deleted file mode 100644
index 769f78c726e8..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.StatsManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IStatsManager;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.util.StatsLog;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-import android.view.MotionEvent;
-import android.view.View.OnFocusChangeListener;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.ConfigMetricsReportList;
-import com.android.os.StatsLog.StatsdStatsReport;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Runs a load test for statsd.
- * How it works:
- * <ul>
- * <li> Sets up and pushes a custom config with metrics that exercise a large swath of code paths.
- * <li> Periodically logs certain atoms into logd.
- * <li> Impact on battery can be printed to logcat, or a bug report can be filed and analyzed
- * in battery Historian.
- * </ul>
- * The load depends on how demanding the config is, as well as how frequently atoms are pushsed
- * to logd. Those are all controlled by 4 adjustable parameters:
- * <ul>
- * <li> The 'replication' parameter artificially multiplies the number of metrics in the config.
- * <li> The bucket size controls the time-bucketing the aggregate metrics.
- * <li> The period parameter controls how frequently atoms are pushed to logd.
- * <li> The 'burst' parameter controls how many atoms are pushed at the same time (per period).
- * </ul>
- */
-public class LoadtestActivity extends Activity implements AdapterView.OnItemSelectedListener {
-
- private static final String TAG = "loadtest.LoadtestActivity";
- public static final String TYPE = "type";
- private static final String PUSH_ALARM = "push_alarm";
- public static final String PERF_ALARM = "perf_alarm";
- private static final String SET_REPLICATION = "set_replication";
- private static final String REPLICATION = "replication";
- private static final String START = "start";
- private static final String STOP = "stop";
- private static final Map<String, TimeUnit> TIME_UNIT_MAP = initializeTimeUnitMap();
- private static final List<String> TIME_UNIT_LABELS = initializeTimeUnitLabels();
-
- public final static class PusherAlarmReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Intent activityIntent = new Intent(context, LoadtestActivity.class);
- activityIntent.putExtra(TYPE, PUSH_ALARM);
- context.startActivity(activityIntent);
- }
- }
-
- public final static class StopperAlarmReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Intent activityIntent = new Intent(context, LoadtestActivity.class);
- activityIntent.putExtra(TYPE, STOP);
- context.startActivity(activityIntent);
- }
- }
-
- private static Map<String, TimeUnit> initializeTimeUnitMap() {
- Map<String, TimeUnit> labels = new HashMap();
- labels.put("1m", TimeUnit.ONE_MINUTE);
- labels.put("5m", TimeUnit.FIVE_MINUTES);
- labels.put("10m", TimeUnit.TEN_MINUTES);
- labels.put("30m", TimeUnit.THIRTY_MINUTES);
- labels.put("1h", TimeUnit.ONE_HOUR);
- labels.put("3h", TimeUnit.THREE_HOURS);
- labels.put("6h", TimeUnit.SIX_HOURS);
- labels.put("12h", TimeUnit.TWELVE_HOURS);
- labels.put("1d", TimeUnit.ONE_DAY);
- labels.put("1s", TimeUnit.CTS);
- return labels;
- }
-
- private static List<String> initializeTimeUnitLabels() {
- List<String> labels = new ArrayList();
- labels.add("1s");
- labels.add("1m");
- labels.add("5m");
- labels.add("10m");
- labels.add("30m");
- labels.add("1h");
- labels.add("3h");
- labels.add("6h");
- labels.add("12h");
- labels.add("1d");
- return labels;
- }
-
- private AlarmManager mAlarmMgr;
-
- /**
- * Used to periodically log atoms to logd.
- */
- private PendingIntent mPushPendingIntent;
-
- /**
- * Used to end the loadtest.
- */
- private PendingIntent mStopPendingIntent;
-
- private Button mStartStop;
- private EditText mReplicationText;
- private Spinner mBucketSpinner;
- private EditText mPeriodText;
- private EditText mBurstText;
- private EditText mDurationText;
- private TextView mReportText;
- private CheckBox mPlaceboCheckBox;
- private CheckBox mCountMetricCheckBox;
- private CheckBox mDurationMetricCheckBox;
- private CheckBox mEventMetricCheckBox;
- private CheckBox mValueMetricCheckBox;
- private CheckBox mGaugeMetricCheckBox;
-
- /**
- * When the load test started.
- */
- private long mStartedTimeMillis;
-
- /**
- * For measuring perf data.
- */
- private PerfData mPerfData;
-
- /**
- * For communicating with statsd.
- */
- private StatsManager mStatsManager;
-
- private PowerManager mPowerManager;
- private WakeLock mWakeLock;
-
- /**
- * If true, we only measure the effect of the loadtest infrastructure. No atom are pushed and
- * the configuration is empty.
- */
- private boolean mPlacebo;
-
- /**
- * Whether to include CountMetric in the config.
- */
- private boolean mIncludeCountMetric;
-
- /**
- * Whether to include DurationMetric in the config.
- */
- private boolean mIncludeDurationMetric;
-
- /**
- * Whether to include EventMetric in the config.
- */
- private boolean mIncludeEventMetric;
-
- /**
- * Whether to include ValueMetric in the config.
- */
- private boolean mIncludeValueMetric;
-
- /**
- * Whether to include GaugeMetric in the config.
- */
- private boolean mIncludeGaugeMetric;
-
- /**
- * The burst size.
- */
- private int mBurst;
-
- /**
- * The metrics replication.
- */
- private int mReplication;
-
- /**
- * The period, in seconds, at which batches of atoms are pushed.
- */
- private long mPeriodSecs;
-
- /**
- * The bucket size, in minutes, for aggregate metrics.
- */
- private TimeUnit mBucket;
-
- /**
- * The duration, in minutes, of the loadtest.
- */
- private long mDurationMins;
-
- /**
- * Whether the loadtest has started.
- */
- private boolean mStarted = false;
-
- /**
- * Orchestrates the logging of pushed events into logd.
- */
- private SequencePusher mPusher;
-
- /**
- * Generates statsd configs.
- */
- private ConfigFactory mFactory;
-
- /**
- * For intra-minute periods.
- */
- private final Handler mHandler = new Handler();
-
- /**
- * Number of metrics in the current config.
- */
- private int mNumMetrics;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- Log.d(TAG, "Starting loadtest Activity");
-
- setContentView(R.layout.activity_loadtest);
- mReportText = (TextView) findViewById(R.id.report_text);
- initBurst();
- initReplication();
- initBucket();
- initPeriod();
- initDuration();
- initPlacebo();
- initMetricWhitelist();
-
- // Hide the keyboard outside edit texts.
- findViewById(R.id.outside).setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- InputMethodManager imm =
- (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- if (getCurrentFocus() != null) {
- imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
- }
- return true;
- }
- });
-
- mStartStop = findViewById(R.id.start_stop);
- mStartStop.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (mStarted) {
- stopLoadtest();
- } else {
- startLoadtest();
- }
- }
- });
-
- mAlarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
- mStatsManager = (StatsManager) getSystemService("stats");
- mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
- mFactory = new ConfigFactory(this);
- stopLoadtest();
- mReportText.setText("");
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- String type = intent.getStringExtra(TYPE);
- if (type == null) {
- return;
- }
- switch (type) {
- case PERF_ALARM:
- onPerfAlarm();
- break;
- case PUSH_ALARM:
- onAlarm();
- break;
- case SET_REPLICATION:
- if (intent.hasExtra(REPLICATION)) {
- setReplication(intent.getIntExtra(REPLICATION, 0));
- }
- break;
- case START:
- startLoadtest();
- break;
- case STOP:
- stopLoadtest();
- break;
- default:
- throw new IllegalArgumentException("Unknown type: " + type);
- }
- }
-
- @Override
- public void onDestroy() {
- Log.d(TAG, "Destroying");
- mPerfData.onDestroy();
- stopLoadtest();
- clearConfigs();
- super.onDestroy();
- }
-
- @Nullable
- public StatsdStatsReport getMetadata() {
- if (!statsdRunning()) {
- return null;
- }
- if (mStatsManager != null) {
- 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;
- try {
- return StatsdStatsReport.parseFrom(data);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- Log.d(TAG, "Bad StatsdStatsReport");
- }
- }
- }
- return null;
- }
-
- @Nullable
- public List<ConfigMetricsReport> getData() {
- if (!statsdRunning()) {
- return null;
- }
- if (mStatsManager != null) {
- 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 {
- reports = ConfigMetricsReportList.parseFrom(data);
- Log.d(TAG, "Num reports: " + reports.getReportsCount());
- StringBuilder sb = new StringBuilder();
- DisplayProtoUtils.displayLogReport(sb, reports);
- Log.d(TAG, sb.toString());
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- Log.d(TAG, "Invalid data");
- }
- if (reports != null) {
- return reports.getReportsList();
- }
- }
- }
- return null;
- }
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- String item = parent.getItemAtPosition(position).toString();
-
- mBucket = TIME_UNIT_MAP.get(item);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // Another interface callback
- }
-
- private void onPerfAlarm() {
- if (mPerfData != null) {
- mPerfData.onAlarm(this);
- }
- // Piggy-back on that alarm to show the elapsed time.
- long elapsedTimeMins = (long) Math.floor(
- (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
- mReportText.setText("Loadtest in progress.\n"
- + "num metrics =" + mNumMetrics
- + "\nElapsed time = " + elapsedTimeMins + " min(s)");
- }
-
- private void onAlarm() {
- Log.d(TAG, "ON ALARM");
-
- // Set the next task.
- scheduleNext();
-
- // Do the work.
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "StatsdLoadTest");
- mWakeLock.acquire();
- if (mPusher != null) {
- mPusher.next();
- }
- mWakeLock.release();
- mWakeLock = null;
- }
-
- /**
- * Schedules the next cycle of pushing atoms into logd.
- */
- private void scheduleNext() {
- Intent intent = new Intent(this, PusherAlarmReceiver.class);
- intent.putExtra(TYPE, PUSH_ALARM);
- mPushPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
- long nextTime = SystemClock.elapsedRealtime() + mPeriodSecs * 1000;
- mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mPushPendingIntent);
- }
-
- private synchronized void startLoadtest() {
- if (mStarted) {
- return;
- }
-
- // Clean up the state.
- stopLoadtest();
-
- // Prepare to push a sequence of atoms to logd.
- mPusher = new SequencePusher(mBurst, mPlacebo);
-
- // Create a config and push it to statsd.
- if (!setConfig(mFactory.getConfig(mReplication, mBucket, mPlacebo,
- mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric,
- mIncludeValueMetric, mIncludeGaugeMetric))) {
- return;
- }
-
- // Remember to stop in the future.
- Intent intent = new Intent(this, StopperAlarmReceiver.class);
- intent.putExtra(TYPE, STOP);
- mStopPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
- long nextTime = SystemClock.elapsedRealtime() + mDurationMins * 60 * 1000;
- mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mStopPendingIntent);
-
- // Log atoms.
- scheduleNext();
-
- // Start tracking performance.
- mPerfData = new PerfData(this, mPlacebo, mReplication, mBucket, mPeriodSecs, mBurst,
- mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric, mIncludeValueMetric,
- mIncludeGaugeMetric);
- mPerfData.startRecording(this);
-
- mReportText.setText("Loadtest in progress.\nnum metrics =" + mNumMetrics);
- mStartedTimeMillis = SystemClock.elapsedRealtime();
-
- updateStarted(true);
- }
-
- private synchronized void stopLoadtest() {
- if (mPushPendingIntent != null) {
- Log.d(TAG, "Canceling pre-existing push alarm");
- mAlarmMgr.cancel(mPushPendingIntent);
- mPushPendingIntent = null;
- }
- if (mStopPendingIntent != null) {
- Log.d(TAG, "Canceling pre-existing stop alarm");
- mAlarmMgr.cancel(mStopPendingIntent);
- mStopPendingIntent = null;
- }
- if (mWakeLock != null) {
- mWakeLock.release();
- mWakeLock = null;
- }
- if (mPerfData != null) {
- mPerfData.stopRecording(this);
- mPerfData.onDestroy();
- mPerfData = null;
- }
-
- // Obtain the latest data and display it.
- getData();
-
- long elapsedTimeMins = (long) Math.floor(
- (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
- mReportText.setText("Loadtest ended. Elapsed time = " + elapsedTimeMins + " min(s)");
- clearConfigs();
- updateStarted(false);
- }
-
- private synchronized void updateStarted(boolean started) {
- mStarted = started;
- mStartStop.setBackgroundColor(started ?
- Color.parseColor("#FFFF0000") : Color.parseColor("#FF00FF00"));
- mStartStop.setText(started ? getString(R.string.stop) : getString(R.string.start));
- updateControlsEnabled();
- }
-
- private void updateControlsEnabled() {
- mBurstText.setEnabled(!mPlacebo && !mStarted);
- mReplicationText.setEnabled(!mPlacebo && !mStarted);
- mPeriodText.setEnabled(!mStarted);
- mBucketSpinner.setEnabled(!mPlacebo && !mStarted);
- mDurationText.setEnabled(!mStarted);
- mPlaceboCheckBox.setEnabled(!mStarted);
-
- boolean enabled = !mStarted && !mPlaceboCheckBox.isChecked();
- mCountMetricCheckBox.setEnabled(enabled);
- mDurationMetricCheckBox.setEnabled(enabled);
- mEventMetricCheckBox.setEnabled(enabled);
- mValueMetricCheckBox.setEnabled(enabled);
- mGaugeMetricCheckBox.setEnabled(enabled);
- }
-
- private boolean statsdRunning() {
- if (IStatsManager.Stub.asInterface(ServiceManager.getService("stats")) == null) {
- Log.d(TAG, "Statsd not running");
- Toast.makeText(LoadtestActivity.this, "Statsd NOT running!", Toast.LENGTH_LONG).show();
- return false;
- }
- return true;
- }
-
- private int sanitizeInt(int val, int min, int max) {
- if (val > max) {
- val = max;
- } else if (val < min) {
- val = min;
- }
- return val;
- }
-
- private void clearConfigs() {
- // TODO: Clear all configs instead of specific ones.
- if (mStatsManager != null) {
- if (mStarted) {
- try {
- mStatsManager.removeConfig(ConfigFactory.CONFIG_ID);
- Log.d(TAG, "Removed loadtest statsd configs.");
- } catch (StatsManager.StatsUnavailableException e) {
- Log.e(TAG, "Failed to remove loadtest configs.", e);
- }
- }
- }
- }
-
- private boolean setConfig(ConfigFactory.ConfigMetadata configData) {
- if (mStatsManager != null) {
- try {
- mStatsManager.addConfig(ConfigFactory.CONFIG_ID, configData.bytes);
- mNumMetrics = configData.numMetrics;
- Log.d(TAG, "Config pushed to statsd");
- return true;
- } catch (StatsManager.StatsUnavailableException | IllegalArgumentException e) {
- Log.e(TAG, "Failed to push config to statsd", e);
- }
- }
- return false;
- }
-
- private synchronized void setReplication(int replication) {
- if (mStarted) {
- return;
- }
- mReplicationText.setText("" + replication);
- }
-
- private synchronized void setPeriodSecs(long periodSecs) {
- mPeriodSecs = periodSecs;
- }
-
- private synchronized void setBurst(int burst) {
- mBurst = burst;
- }
-
- private synchronized void setDurationMins(long durationMins) {
- mDurationMins = durationMins;
- }
-
-
- private void handleFocus(EditText editText) {
- /*
- editText.setOnFocusChangeListener(new OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (!hasFocus && editText.getText().toString().isEmpty()) {
- editText.setText("-1", TextView.BufferType.EDITABLE);
- }
- }
- });
- */
- }
-
- private void initBurst() {
- mBurst = getResources().getInteger(R.integer.burst_default);
- mBurstText = (EditText) findViewById(R.id.burst);
- mBurstText.addTextChangedListener(new NumericalWatcher(mBurstText, 0, 1000) {
- @Override
- public void onNewValue(int newValue) {
- setBurst(newValue);
- }
- });
- handleFocus(mBurstText);
- }
-
- private void initReplication() {
- mReplication = getResources().getInteger(R.integer.replication_default);
- mReplicationText = (EditText) findViewById(R.id.replication);
- mReplicationText.addTextChangedListener(new NumericalWatcher(mReplicationText, 1, 4096) {
- @Override
- public void onNewValue(int newValue) {
- mReplication = newValue;
- }
- });
- handleFocus(mReplicationText);
- }
-
- private void initBucket() {
- String defaultValue = getResources().getString(R.string.bucket_default);
- mBucket = TimeUnit.valueOf(defaultValue);
- mBucketSpinner = (Spinner) findViewById(R.id.bucket_spinner);
-
- ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(
- this, R.layout.spinner_item, TIME_UNIT_LABELS);
-
- mBucketSpinner.setAdapter(dataAdapter);
- mBucketSpinner.setOnItemSelectedListener(this);
-
- for (String label : TIME_UNIT_MAP.keySet()) {
- if (defaultValue.equals(TIME_UNIT_MAP.get(label).toString())) {
- mBucketSpinner.setSelection(dataAdapter.getPosition(label));
- }
- }
- }
-
- private void initPeriod() {
- mPeriodSecs = getResources().getInteger(R.integer.period_default);
- mPeriodText = (EditText) findViewById(R.id.period);
- mPeriodText.addTextChangedListener(new NumericalWatcher(mPeriodText, 1, 60) {
- @Override
- public void onNewValue(int newValue) {
- setPeriodSecs(newValue);
- }
- });
- handleFocus(mPeriodText);
- }
-
- private void initDuration() {
- mDurationMins = getResources().getInteger(R.integer.duration_default);
- mDurationText = (EditText) findViewById(R.id.duration);
- mDurationText.addTextChangedListener(new NumericalWatcher(mDurationText, 1, 24 * 60) {
- @Override
- public void onNewValue(int newValue) {
- setDurationMins(newValue);
- }
- });
- handleFocus(mDurationText);
- }
-
- private void initPlacebo() {
- mPlaceboCheckBox = findViewById(R.id.placebo);
- mPlacebo = false;
- mPlaceboCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mPlacebo = mPlaceboCheckBox.isChecked();
- updateControlsEnabled();
- }
- });
- }
-
- private void initMetricWhitelist() {
- mCountMetricCheckBox = findViewById(R.id.include_count);
- mCountMetricCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mIncludeCountMetric = mCountMetricCheckBox.isChecked();
- }
- });
- mDurationMetricCheckBox = findViewById(R.id.include_duration);
- mDurationMetricCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mIncludeDurationMetric = mDurationMetricCheckBox.isChecked();
- }
- });
- mEventMetricCheckBox = findViewById(R.id.include_event);
- mEventMetricCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mIncludeEventMetric = mEventMetricCheckBox.isChecked();
- }
- });
- mValueMetricCheckBox = findViewById(R.id.include_value);
- mValueMetricCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mIncludeValueMetric = mValueMetricCheckBox.isChecked();
- }
- });
- mGaugeMetricCheckBox = findViewById(R.id.include_gauge);
- mGaugeMetricCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mIncludeGaugeMetric = mGaugeMetricCheckBox.isChecked();
- }
- });
-
- mIncludeCountMetric = mCountMetricCheckBox.isChecked();
- mIncludeDurationMetric = mDurationMetricCheckBox.isChecked();
- mIncludeEventMetric = mEventMetricCheckBox.isChecked();
- mIncludeValueMetric = mValueMetricCheckBox.isChecked();
- mIncludeGaugeMetric = mGaugeMetricCheckBox.isChecked();
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java
deleted file mode 100644
index 01eebf2ad1cf..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.os.SystemClock;
-import android.util.Log;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/** Parses PSS info from dumpsys meminfo */
-public class MemInfoParser implements PerfParser {
-
- private static final Pattern LINE_PATTERN =
- Pattern.compile("\\s*(\\d*,*\\d*)K:\\s(\\S*)\\s\\.*");
- private static final String PSS_BY_PROCESS = "Total PSS by process:";
- private static final String TAG = "loadtest.MemInfoParser";
-
- private boolean mPssStarted;
- private boolean mPssEnded;
- private final long mStartTimeMillis;
-
- public MemInfoParser(long startTimeMillis) {
- mStartTimeMillis = startTimeMillis;
- }
-
- @Override
- @Nullable
- public String parseLine(String line) {
- if (mPssEnded) {
- return null;
- }
- if (!mPssStarted) {
- if (line.contains(PSS_BY_PROCESS)) {
- mPssStarted = true;
- }
- return null;
- }
- if (line.isEmpty()) {
- mPssEnded = true;
- return null;
- }
- Matcher lineMatcher = LINE_PATTERN.matcher(line);
- if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
- if (lineMatcher.group(2).equals("statsd")) {
- long timeDeltaMillis = SystemClock.elapsedRealtime() - mStartTimeMillis;
- return timeDeltaMillis + "," + convertToPss(lineMatcher.group(1));
- }
- }
- return null;
- }
-
- private String convertToPss(String input) {
- return input.replace(",", "");
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
deleted file mode 100644
index af7bd4d35966..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.content.Context;
-import android.os.SystemClock;
-import android.util.Log;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-public class MemoryDataRecorder extends PerfDataRecorder {
- private static final String TAG = "loadtest.MemoryDataDataRecorder";
- private static final String DUMP_FILENAME = TAG + "_dump.tmp";
-
- private long mStartTimeMillis;
- private StringBuilder mSb;
-
- public MemoryDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
- int burst, boolean includeCountMetric, boolean includeDurationMetric,
- boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
- super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
- includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
- }
-
- @Override
- public void startRecording(Context context) {
- mStartTimeMillis = SystemClock.elapsedRealtime();
- mSb = new StringBuilder();
- }
-
- @Override
- public void onAlarm(Context context) {
- runDumpsysStats(context, DUMP_FILENAME, "meminfo");
- readDumpData(context, DUMP_FILENAME, new MemInfoParser(mStartTimeMillis), mSb);
- }
-
- @Override
- public void stopRecording(Context context) {
- writeData(context, "meminfo_", "time,pss", mSb);
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
deleted file mode 100644
index 555e6dd2d99d..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.widget.TextView;
-
-public abstract class NumericalWatcher implements TextWatcher {
-
- private static final String TAG = "loadtest.NumericalWatcher";
-
- private final TextView mTextView;
- private final int mMin;
- private final int mMax;
- private int currentValue = -1;
-
- public NumericalWatcher(TextView textView, int min, int max) {
- mTextView = textView;
- mMin = min;
- mMax = max;
- }
-
- public abstract void onNewValue(int newValue);
-
- @Override
- final public void afterTextChanged(Editable editable) {
- String s = mTextView.getText().toString();
- if (s.isEmpty()) {
- return;
- }
- int unsanitized = Integer.parseInt(s);
- int newValue = sanitize(unsanitized);
- if (currentValue != newValue || unsanitized != newValue) {
- currentValue = newValue;
- editable.clear();
- editable.append(newValue + "");
- }
- onNewValue(newValue);
- }
-
- @Override
- final public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
- @Override
- final public void onTextChanged(CharSequence s, int start, int before, int count) {}
-
- private int sanitize(int val) {
- if (val > mMax) {
- val = mMax;
- } else if (val < mMin) {
- val = mMin;
- }
- return val;
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
deleted file mode 100644
index 7a01adedfaa4..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/** Prints some information about the device via Dumpsys in order to evaluate health metrics. */
-public class PerfData extends PerfDataRecorder {
-
- private static final String TAG = "loadtest.PerfData";
-
- /** Polling period for performance snapshots like memory. */
- private static final long POLLING_PERIOD_MILLIS = 1 * 60 * 1000;
-
- public final static class PerfAlarmReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Intent activityIntent = new Intent(context, LoadtestActivity.class);
- activityIntent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
- context.startActivity(activityIntent);
- }
- }
-
- private AlarmManager mAlarmMgr;
-
- /** Used to periodically poll some dumpsys data. */
- private PendingIntent mPendingIntent;
-
- private final Set<PerfDataRecorder> mRecorders;
-
- public PerfData(LoadtestActivity loadtestActivity, boolean placebo, int replication,
- TimeUnit bucket, long periodSecs, int burst, boolean includeCountMetric,
- boolean includeDurationMetric, boolean includeEventMetric, boolean includeValueMetric,
- boolean includeGaugeMetric) {
- super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
- includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
- mRecorders = new HashSet();
- mRecorders.add(new BatteryDataRecorder(placebo, replication, bucket, periodSecs, burst,
- includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
- includeGaugeMetric));
- mRecorders.add(new MemoryDataRecorder(placebo, replication, bucket, periodSecs, burst,
- includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
- includeGaugeMetric));
- mRecorders.add(new StatsdStatsRecorder(loadtestActivity, placebo, replication, bucket,
- periodSecs, burst, includeCountMetric, includeDurationMetric, includeEventMetric,
- includeValueMetric, includeGaugeMetric));
- mRecorders.add(new ValidationRecorder(loadtestActivity, placebo, replication, bucket,
- periodSecs, burst, includeCountMetric, includeDurationMetric, includeEventMetric,
- includeValueMetric, includeGaugeMetric));
- mAlarmMgr = (AlarmManager) loadtestActivity.getSystemService(Context.ALARM_SERVICE);
- }
-
- public void onDestroy() {
- if (mPendingIntent != null) {
- mAlarmMgr.cancel(mPendingIntent);
- mPendingIntent = null;
- }
- }
-
- @Override
- public void startRecording(Context context) {
- Intent intent = new Intent(context, PerfAlarmReceiver.class);
- intent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
- mPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
- mAlarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, -1 /* now */,
- POLLING_PERIOD_MILLIS, mPendingIntent);
-
- for (PerfDataRecorder recorder : mRecorders) {
- recorder.startRecording(context);
- }
- }
-
- @Override
- public void onAlarm(Context context) {
- for (PerfDataRecorder recorder : mRecorders) {
- recorder.onAlarm(context);
- }
- }
-
- @Override
- public void stopRecording(Context context) {
- if (mPendingIntent != null) {
- mAlarmMgr.cancel(mPendingIntent);
- mPendingIntent = null;
- }
-
- for (PerfDataRecorder recorder : mRecorders) {
- recorder.stopRecording(context);
- }
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java
deleted file mode 100644
index 8613ac1c4796..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Environment;
-import android.util.Log;
-import android.os.Debug;
-
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-public abstract class PerfDataRecorder {
- private static final String TAG = "loadtest.PerfDataRecorder";
-
- protected final String mTimeAsString;
- protected final String mColumnSuffix;
-
- protected PerfDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
- int burst, boolean includeCountMetric, boolean includeDurationMetric,
- boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
- mTimeAsString = new SimpleDateFormat("YYYY_MM_dd_HH_mm_ss").format(new Date());
- mColumnSuffix = getColumnSuffix(placebo, replication, bucket, periodSecs, burst,
- includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
- includeGaugeMetric);
- }
-
- /** Starts recording performance data. */
- public abstract void startRecording(Context context);
-
- /** Called periodically. For the recorder to sample data, if needed. */
- public abstract void onAlarm(Context context);
-
- /** Stops recording performance data, and writes it to disk. */
- public abstract void stopRecording(Context context);
-
- /** Runs the dumpsys command. */
- protected void runDumpsysStats(Context context, String dumpFilename, String cmd,
- String... args) {
- boolean success = false;
- // Call dumpsys Dump statistics to a file.
- FileOutputStream fo = null;
- try {
- fo = context.openFileOutput(dumpFilename, Context.MODE_PRIVATE);
- if (!Debug.dumpService(cmd, fo.getFD(), args)) {
- Log.w(TAG, "Dumpsys failed.");
- }
- success = true;
- } catch (IOException | SecurityException | NullPointerException e) {
- // SecurityException may occur when trying to dump multi-user info.
- // NPE can occur during dumpService (root cause unknown).
- throw new RuntimeException(e);
- } finally {
- closeQuietly(fo);
- }
- }
-
- /**
- * Reads a text file and parses each line, one by one. The result of the parsing is stored
- * in the passed {@link StringBuffer}.
- */
- protected void readDumpData(Context context, String dumpFilename, PerfParser parser,
- StringBuilder sb) {
- FileInputStream fi = null;
- BufferedReader br = null;
- try {
- fi = context.openFileInput(dumpFilename);
- br = new BufferedReader(new InputStreamReader(fi));
- String line = br.readLine();
- while (line != null) {
- String recordLine = parser.parseLine(line);
- if (recordLine != null) {
- sb.append(recordLine).append('\n');
- }
- line = br.readLine();
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
- closeQuietly(br);
- }
- }
-
- /** Writes CSV data to a file. */
- protected void writeData(Context context, String filePrefix, String columnPrefix,
- StringBuilder sb) {
- File dataFile = new File(getStorageDir(), filePrefix + mTimeAsString + ".csv");
-
- FileWriter writer = null;
- try {
- writer = new FileWriter(dataFile);
- writer.append(columnPrefix + mColumnSuffix + "\n");
- writer.append(sb.toString());
- writer.flush();
- Log.d(TAG, "Finished writing data at " + dataFile.getAbsolutePath());
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
- closeQuietly(writer);
- }
- }
-
- /** Gets the suffix to use in the column name for perf data. */
- private String getColumnSuffix(boolean placebo, int replication, TimeUnit bucket,
- long periodSecs, int burst, boolean includeCountMetric, boolean includeDurationMetric,
- boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
- if (placebo) {
- return "_placebo_p=" + periodSecs;
- }
- StringBuilder sb = new StringBuilder()
- .append("_r=" + replication)
- .append("_bkt=" + bucket)
- .append("_p=" + periodSecs)
- .append("_bst=" + burst)
- .append("_m=");
- if (includeCountMetric) {
- sb.append("c");
- }
- if (includeEventMetric) {
- sb.append("e");
- }
- if (includeDurationMetric) {
- sb.append("d");
- }
- if (includeGaugeMetric) {
- sb.append("g");
- }
- if (includeValueMetric) {
- sb.append("v");
- }
- return sb.toString();
- }
-
- private File getStorageDir() {
- File file = new File(Environment.getExternalStoragePublicDirectory(
- Environment.DIRECTORY_DOCUMENTS), "loadtest/" + mTimeAsString);
- if (!file.mkdirs()) {
- Log.e(TAG, "Directory not created");
- }
- return file;
- }
-
- private void closeQuietly(@Nullable Closeable c) {
- if (c != null) {
- try {
- c.close();
- } catch (IOException ignore) {
- }
- }
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
deleted file mode 100644
index e000918fa0f7..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.annotation.Nullable;
-
-public interface PerfParser {
-
- /**
- * Parses one line of the dumpsys output, and returns a string to write to the data file,
- * or null if no string should be written.
- */
- @Nullable String parseLine(String line);
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
deleted file mode 100644
index 5dcce9acb401..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.util.Log;
-import android.util.StatsLog;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Manages the pushing of atoms into logd for loadtesting.
- * We rely on small number of pushed atoms, and a config with metrics based on those atoms.
- * The atoms are:
- * <ul>
- * <li> BatteryLevelChanged - For EventMetric, CountMetric and GaugeMetric (no dimensions).
- * <li> BleScanResultReceived - For CountMetric and ValueMetric, sliced by uid.
- * <li> ChargingStateChanged - For DurationMetric (no dimension).
- * <li> GpsScanStateChanged - For DurationMetric, sliced by uid.
- * <li> ScreenStateChanged - For Conditions with no dimensions.
- * <li> AudioStateChanged - For Conditions with dimensions (uid).
- * </ul>
- * The sequence is played over and over at a given frequency.
- */
-public class SequencePusher {
- private static final String TAG = "SequencePusher";
-
- /** Some atoms are pushed in burst of {@code mBurst} events. */
- private final int mBurst;
-
- /** If this is true, we don't log anything in logd. */
- private final boolean mPlacebo;
-
- /** Current state in the automaton. */
- private int mCursor = 0;
-
- public SequencePusher(int burst, boolean placebo) {
- mBurst = burst;
- mPlacebo = placebo;
- }
-
- /**
- * Pushes the next atom to logd.
- * This follows a small automaton which makes the right events and conditions overlap:
- * (0) Push a burst of BatteryLevelChanged atoms.
- * (1) Push a burst of BleScanResultReceived atoms.
- * (2) Push ChargingStateChanged with BATTERY_STATUS_CHARGING once.
- * (3) Push a burst of GpsScanStateChanged atoms with ON, with a different uid each time.
- * (4) Push ChargingStateChanged with BATTERY_STATUS_NOT_CHARGING once.
- * (5) Push a burst GpsScanStateChanged atoms with OFF, with a different uid each time.
- * (6) Push ScreenStateChanged with STATE_ON once.
- * (7) Push a burst of AudioStateChanged with ON, with a different uid each time.
- * (8) Repeat steps (0)-(5).
- * (9) Push ScreenStateChanged with STATE_OFF once.
- * (10) Push a burst of AudioStateChanged with OFF, with a different uid each time.
- * and repeat.
- */
- public void next() {
- Log.d(TAG, "Next step: " + mCursor);
- if (mPlacebo) {
- return;
- }
- switch (mCursor) {
- case 0:
- case 8:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.BATTERY_LEVEL_CHANGED, 50 + i /* battery_level */);
- }
- break;
- case 1:
- case 9:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED, i /* uid */,
- 100 /* num_of_results */);
- }
- break;
- case 2:
- case 10:
- StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
- StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_CHARGING
- /* charging_state */);
- break;
- case 3:
- case 11:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
- StatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON /* state */);
- }
- break;
- case 4:
- case 12:
- StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
- StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
- /* charging_state */);
- break;
- case 5:
- case 13:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
- StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
- }
- break;
- case 6:
- StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
- StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON /* display_state */);
- break;
- case 7:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
- StatsLog.AUDIO_STATE_CHANGED__STATE__ON /* state */);
- }
- break;
- case 14:
- StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
- StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
- break;
- case 15:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
- StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
- }
- break;
- default:
- }
- mCursor++;
- if (mCursor > 15) {
- mCursor = 0;
- }
- }
-
- /**
- * Properly finishes in order to be close all conditions and durations.
- */
- public void finish() {
- // Screen goes back to off. This will ensure that conditions get back to false.
- StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
- StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
- StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
- }
- // Stop charging, to ensure the corresponding durations are closed.
- StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
- StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
- /* charging_state */);
- // Stop scanning GPS, to ensure the corresponding conditions get back to false.
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
- StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
- }
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java
deleted file mode 100644
index 3939e7e0b2fa..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.content.Context;
-import com.android.os.StatsLog.StatsdStatsReport;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-public class StatsdStatsRecorder extends PerfDataRecorder {
- private static final String TAG = "loadtest.StatsdStatsRecorder";
-
- private final LoadtestActivity mLoadtestActivity;
-
- public StatsdStatsRecorder(LoadtestActivity loadtestActivity, boolean placebo, int replication,
- TimeUnit bucket, long periodSecs, int burst, boolean includeCountMetric,
- boolean includeDurationMetric, boolean includeEventMetric, boolean includeValueMetric,
- boolean includeGaugeMetric) {
- super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
- includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
- mLoadtestActivity = loadtestActivity;
- }
-
- @Override
- public void startRecording(Context context) {
- // Nothing to do.
- }
-
- @Override
- public void onAlarm(Context context) {
- // Nothing to do.
- }
-
- @Override
- public void stopRecording(Context context) {
- StatsdStatsReport metadata = mLoadtestActivity.getMetadata();
- if (metadata != null) {
- int numConfigs = metadata.getConfigStatsCount();
- StringBuilder sb = new StringBuilder();
- StatsdStatsReport.ConfigStats configStats = metadata.getConfigStats(numConfigs - 1);
- sb.append("metric_count,")
- .append(configStats.getMetricCount() + "\n")
- .append("condition_count,")
- .append(configStats.getConditionCount() + "\n")
- .append("matcher_count,")
- .append(configStats.getMatcherCount() + "\n");
- writeData(context, "statsdstats_", "stat,value", sb);
- }
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
deleted file mode 100644
index d9f0ca9d2461..000000000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2017 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.statsd.loadtest;
-
-import android.content.Context;
-import android.util.Log;
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.EventMetricData;
-import com.android.os.StatsLog.StatsLogReport;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Checks the correctness of the stats.
- */
-public class ValidationRecorder extends PerfDataRecorder {
- private static final String TAG = "loadtest.ValidationRecorder";
-
- private final LoadtestActivity mLoadtestActivity;
-
- public ValidationRecorder(LoadtestActivity loadtestActivity, boolean placebo, int replication,
- TimeUnit bucket, long periodSecs, int burst, boolean includeCountMetric,
- boolean includeDurationMetric, boolean includeEventMetric, boolean includeValueMetric,
- boolean includeGaugeMetric) {
- super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
- includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
- mLoadtestActivity = loadtestActivity;
- }
-
- @Override
- public void startRecording(Context context) {
- // Nothing to do.
- }
-
- @Override
- public void onAlarm(Context context) {
- validateData();
- }
-
- @Override
- public void stopRecording(Context context) {
- validateData();
- }
-
- private void validateData() {
- // The code below is commented out because it calls getData, which has the side-effect
- // of clearing statsd's data buffer.
- /*
- List<ConfigMetricsReport> reports = mLoadtestActivity.getData();
- if (reports != null) {
- Log.d(TAG, "GOT DATA");
- for (ConfigMetricsReport report : reports) {
- for (StatsLogReport logReport : report.getMetricsList()) {
- if (!logReport.hasMetricId()) {
- Log.e(TAG, "Metric missing name.");
- }
- }
- }
- }
- */
- }
-
- private void validateEventBatteryLevelChanges(StatsLogReport logReport) {
- Log.d(TAG, "Validating " + logReport.getMetricId());
- if (logReport.hasEventMetrics()) {
- Log.d(TAG, "Num events captured: " + logReport.getEventMetrics().getDataCount());
- for (EventMetricData data : logReport.getEventMetrics().getDataList()) {
- Log.d(TAG, " Event : " + data.getAtom());
- }
- } else {
- Log.d(TAG, "Metric is invalid");
- }
- }
-
- private void validateEventBatteryLevelChangesWhileScreenIsOn(StatsLogReport logReport) {
- Log.d(TAG, "Validating " + logReport.getMetricId());
- }
-}