summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java2
-rw-r--r--apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java2
-rw-r--r--apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java2
-rw-r--r--apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java2
-rw-r--r--apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java4
-rw-r--r--api/system-current.txt1
-rw-r--r--api/system-removed.txt4
-rw-r--r--cmds/bootanimation/Android.mk7
-rw-r--r--cmds/bootanimation/iot/iotbootanimation_main.cpp13
-rw-r--r--cmds/statsd/Android.mk36
-rw-r--r--cmds/statsd/src/PackageInfoListener.h (renamed from core/tests/coretests/src/android/print/PrintTestActivity.java)32
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp36
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h9
-rw-r--r--cmds/statsd/src/StatsService.cpp49
-rw-r--r--cmds/statsd/src/StatsService.h15
-rw-r--r--cmds/statsd/src/UidMap.cpp164
-rw-r--r--cmds/statsd/src/UidMap.h97
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.cpp136
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.h57
-rw-r--r--cmds/statsd/src/condition/ConditionTracker.h105
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp133
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.h64
-rw-r--r--cmds/statsd/src/condition/condition_util.cpp93
-rw-r--r--cmds/statsd/src/condition/condition_util.h (renamed from cmds/statsd/src/metrics/ConditionTracker.h)36
-rw-r--r--cmds/statsd/src/main.cpp3
-rw-r--r--cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp121
-rw-r--r--cmds/statsd/src/matchers/CombinationLogMatchingTracker.h57
-rw-r--r--cmds/statsd/src/matchers/LogMatchingTracker.h95
-rw-r--r--cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp75
-rw-r--r--cmds/statsd/src/matchers/SimpleLogMatchingTracker.h56
-rw-r--r--cmds/statsd/src/matchers/matcher_util.cpp (renamed from cmds/statsd/src/matchers/LogEntryMatcherManager.cpp)119
-rw-r--r--cmds/statsd/src/matchers/matcher_util.h (renamed from cmds/statsd/src/matchers/LogEntryMatcherManager.h)33
-rw-r--r--cmds/statsd/src/metrics/ConditionTracker.cpp54
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp32
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.h23
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h14
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp135
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h55
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp200
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.h94
-rw-r--r--cmds/statsd/src/parse_util.cpp132
-rw-r--r--cmds/statsd/src/stats_log.proto41
-rw-r--r--cmds/statsd/src/stats_util.cpp289
-rw-r--r--cmds/statsd/src/stats_util.h (renamed from cmds/statsd/src/parse_util.h)3
-rw-r--r--cmds/statsd/src/statsd_config.proto21
-rw-r--r--cmds/statsd/tests/ConditionTracker_test.cpp162
-rw-r--r--cmds/statsd/tests/LogEntryMatcher_test.cpp233
-rw-r--r--cmds/statsd/tests/MetricsManager_test.cpp231
-rw-r--r--cmds/statsd/tests/UidMap_test.cpp69
-rw-r--r--core/java/android/app/StatusBarManager.java5
-rw-r--r--core/java/android/app/job/JobScheduler.java41
-rw-r--r--core/java/android/app/job/JobService.java102
-rw-r--r--core/java/android/content/res/ResourcesImpl.java2
-rw-r--r--core/java/android/os/IStatsManager.aidl16
-rw-r--r--core/java/android/text/DynamicLayout.java6
-rw-r--r--core/java/android/text/Layout.java14
-rw-r--r--core/java/android/text/StaticLayout.java23
-rw-r--r--core/java/android/text/TextLine.java10
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java4
-rw-r--r--core/java/com/android/internal/os/LoggingPrintStream.java5
-rw-r--r--core/jni/android_text_StaticLayout.cpp12
-rw-r--r--core/jni/eventlog_helper.h103
-rw-r--r--core/res/res/values-mcc001-mnc01/strings.xml22
-rw-r--r--core/res/res/values-mcc310-mnc030/strings.xml1
-rw-r--r--core/res/res/values-mcc310-mnc150/strings.xml22
-rw-r--r--core/res/res/values-mcc310-mnc170/strings.xml1
-rw-r--r--core/res/res/values-mcc310-mnc280/strings.xml1
-rw-r--r--core/res/res/values-mcc310-mnc410/strings.xml1
-rw-r--r--core/res/res/values-mcc310-mnc560/strings.xml1
-rw-r--r--core/res/res/values-mcc310-mnc950/strings.xml1
-rw-r--r--core/res/res/values-mcc311-mnc180/strings.xml1
-rw-r--r--core/res/res/values-mcc312-mnc670/strings.xml22
-rw-r--r--core/res/res/values-mcc313-mnc100/strings.xml22
-rw-r--r--core/tests/coretests/Android.mk3
-rw-r--r--core/tests/coretests/AndroidManifest.xml12
-rw-r--r--core/tests/coretests/src/android/print/BasePrintTest.java324
-rw-r--r--core/tests/coretests/src/android/print/IPrintManagerParametersTest.java102
-rw-r--r--core/tests/coretests/src/android/print/mockservice/MockPrintService.java40
-rw-r--r--core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java39
-rw-r--r--core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java51
-rw-r--r--core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java52
-rw-r--r--core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java95
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java50
-rw-r--r--media/java/android/media/tv/ITvInputHardware.aidl6
-rw-r--r--media/java/android/media/tv/TvInputManager.java7
-rw-r--r--media/jni/android_media_MediaPlayer.cpp2
-rw-r--r--packages/PrintSpooler/tests/outofprocess/Android.mk2
-rw-r--r--packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml12
-rw-r--r--packages/PrintSpooler/tests/outofprocess/res/values/themes.xml22
-rw-r--r--packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml2
-rw-r--r--packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/BasePrintTest.java275
-rw-r--r--packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/PrintTestActivity.java32
-rw-r--r--packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java30
-rw-r--r--packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/AddPrintersActivity.java52
-rw-r--r--packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/MockPrintService.java40
-rw-r--r--packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrintServiceCallbacks.java39
-rw-r--r--packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrinterDiscoverySessionCallbacks.java51
-rw-r--r--packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrintService.java52
-rw-r--r--packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrinterDiscoverySession.java95
-rw-r--r--packages/SettingsLib/res/values/strings.xml10
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/development/AbstractLogdSizePreferenceController.java12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java85
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractConnectivityPreferenceController.java114
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractImsStatusPreferenceController.java95
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java112
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java119
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java88
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java22
-rw-r--r--packages/SettingsLib/tests/robotests/Android.mk7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java11
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java10
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java125
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropertiesTestImpl.java4
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java107
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java123
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java112
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java85
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java102
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java114
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java10
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java38
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/SettingsLibShadowResources.java2
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeUi.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java2
-rw-r--r--proto/src/metrics_constants.proto3
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java1
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java52
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java33
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java4
-rw-r--r--services/core/java/com/android/server/policy/GlobalActions.java3
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java98
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java1
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java7
-rw-r--r--services/core/java/com/android/server/tv/TvInputHardwareManager.java14
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java11
-rw-r--r--services/net/java/android/net/ip/ConnectivityPacketTracker.java23
-rw-r--r--services/net/java/android/net/ip/IpManager.java26
-rw-r--r--services/net/java/android/net/util/SharedLog.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java6
148 files changed, 5028 insertions, 2245 deletions
diff --git a/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java
index 47dd257b06b5..586c3852325a 100644
--- a/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java
@@ -46,7 +46,7 @@ public class BoringLayoutCreateDrawPerfTest {
private static final float SPACING_ADD = 10f;
private static final float SPACING_MULT = 1.5f;
- @Parameterized.Parameters(name = "cached={3},{1} chars,{0}")
+ @Parameterized.Parameters(name = "cached={3},{1}chars,{0}")
public static Collection cases() {
final List<Object[]> params = new ArrayList<>();
for (int length : new int[]{128}) {
diff --git a/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java b/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java
index 34de65de2627..9d11f29557d2 100644
--- a/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java
@@ -40,7 +40,7 @@ public class BoringLayoutIsBoringPerfTest {
private static final boolean[] BOOLEANS = new boolean[]{false, true};
- @Parameterized.Parameters(name = "cached={4},{1} chars,{0}")
+ @Parameterized.Parameters(name = "cached={4},{1}chars,{0}")
public static Collection cases() {
final List<Object[]> params = new ArrayList<>();
for (int length : new int[]{128}) {
diff --git a/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java
index 00b60add5b15..676879857491 100644
--- a/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java
@@ -42,7 +42,7 @@ public class PaintMeasureDrawPerfTest {
private static final boolean[] BOOLEANS = new boolean[]{false, true};
- @Parameterized.Parameters(name = "cached={1},{0} chars")
+ @Parameterized.Parameters(name = "cached={1},{0}chars")
public static Collection cases() {
final List<Object[]> params = new ArrayList<>();
for (int length : new int[]{128}) {
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java
index 356e2e0dab3c..bfdb7589bdff 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java
@@ -50,7 +50,7 @@ public class StaticLayoutCreateDrawPerfTest {
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
- @Parameterized.Parameters(name = "cached={3},{1} chars,{0}")
+ @Parameterized.Parameters(name = "cached={3},{1}chars,{0}")
public static Collection cases() {
final List<Object[]> params = new ArrayList<>();
for (int length : new int[]{128}) {
diff --git a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
index a2bf33e1f607..ff2d57edb11b 100644
--- a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
@@ -40,7 +40,7 @@ import java.util.Locale;
import java.util.Random;
/**
- * Performance test for multi line, single style {@link StaticLayout} creation/draw.
+ * Performance test for {@link TextView} measure/draw.
*/
@LargeTest
@RunWith(Parameterized.class)
@@ -51,7 +51,7 @@ public class TextViewSetTextMeasurePerfTest {
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
- @Parameterized.Parameters(name = "cached={3},{1} chars,{0}")
+ @Parameterized.Parameters(name = "cached={3},{1}chars,{0}")
public static Collection cases() {
final List<Object[]> params = new ArrayList<>();
for (int length : new int[]{128}) {
diff --git a/api/system-current.txt b/api/system-current.txt
index ea077fe62aee..9e02b03c0add 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -27217,7 +27217,6 @@ package android.media.tv {
}
public static final class TvInputManager.Hardware {
- method public boolean dispatchKeyEventToHdmi(android.view.KeyEvent);
method public void overrideAudioSink(int, java.lang.String, int, int, int);
method public void setStreamVolume(float);
method public boolean setSurface(android.view.Surface, android.media.tv.TvStreamConfig);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 7ee261e88fc7..639877fae6e2 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -275,6 +275,10 @@ package android.media.tv {
method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
}
+ public static final class TvInputManager.Hardware {
+ method public boolean dispatchKeyEventToHdmi(android.view.KeyEvent);
+ }
+
public class TvView extends android.view.ViewGroup {
method public void requestUnblockContent(android.media.tv.TvContentRating);
}
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index b16188e9d82e..e5d35b3b8a0e 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -34,13 +34,6 @@ LOCAL_SRC_FILES += \
iot/BootAction.cpp \
iot/BootParameters.cpp \
-LOCAL_SHARED_LIBRARIES += \
- libandroidthings \
- libbase \
- libbinder \
-
-LOCAL_STATIC_LIBRARIES += cpufeatures
-
else
LOCAL_SRC_FILES += \
diff --git a/cmds/bootanimation/iot/iotbootanimation_main.cpp b/cmds/bootanimation/iot/iotbootanimation_main.cpp
index 742f9c24f3a0..00cef430135e 100644
--- a/cmds/bootanimation/iot/iotbootanimation_main.cpp
+++ b/cmds/bootanimation/iot/iotbootanimation_main.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "IotBootAnimation"
-#include <android-base/file.h>
+#include <base/files/file_util.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
@@ -31,13 +31,14 @@
#include "BootParameters.h"
using namespace android;
-using android::base::ReadFileToString;
// Create a typedef for readability.
typedef android::BootAnimation::Animation Animation;
namespace {
+constexpr const char* kDefaultLibName = "libbootaction.so";
+
class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks {
public:
BootActionAnimationCallbacks(std::unique_ptr<BootParameters> bootParameters)
@@ -49,11 +50,13 @@ public:
// This value is optionally provided by the user and will be written to
// /oem/oem.prop.
char property[PROP_VALUE_MAX] = {0};
- if (property_get("ro.oem.bootactions.lib", property, "") < 1) {
- ALOGI("No bootaction specified");
+ property_get("ro.oem.bootactions.lib", property, kDefaultLibName);
+ library_path += property;
+
+ if (!::base::PathExists(::base::FilePath(library_path))) {
+ ALOGI("Skipping boot actions: %s does not exist", library_path.c_str());
return;
}
- library_path += property;
mBootAction = new BootAction();
if (!mBootAction->init(library_path, mBootParameters->getParameters())) {
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index ca36d27cf684..c5b3b68a44b7 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -42,24 +42,7 @@ LOCAL_MODULE := statsd
LOCAL_SRC_FILES := \
../../core/java/android/os/IStatsCompanionService.aidl \
../../core/java/android/os/IStatsManager.aidl \
- src/StatsService.cpp \
- src/AnomalyMonitor.cpp \
- src/LogEntryPrinter.cpp \
- src/LogReader.cpp \
- src/main.cpp \
- src/DropboxWriter.cpp \
- src/parse_util.cpp \
- src/StatsLogProcessor.cpp \
- src/stats_log.proto \
- src/statsd_config.proto \
- src/StatsPullerManager.cpp \
- src/KernelWakelockPuller.cpp \
- src/DropboxReader.cpp \
- src/matchers/LogEntryMatcherManager.cpp \
- src/metrics/CountMetricProducer.cpp \
- src/metrics/ConditionTracker.cpp \
- src/metrics/MetricsManager.cpp \
- src/metrics/CountAnomalyTracker.cpp \
+ $(call all-cpp-files-under,src) \
LOCAL_CFLAGS += \
-Wall \
@@ -129,13 +112,20 @@ LOCAL_SRC_FILES := \
../../core/java/android/os/IStatsCompanionService.aidl \
../../core/java/android/os/IStatsManager.aidl \
src/StatsService.cpp \
- tests/indexed_priority_queue_test.cpp \
- src/parse_util.cpp \
+ src/stats_util.cpp \
src/LogEntryPrinter.cpp \
src/LogReader.cpp \
- src/matchers/LogEntryMatcherManager.cpp \
- tests/LogReader_test.cpp \
- tests/LogEntryMatcher_test.cpp \
+ src/matchers/matcher_util.cpp \
+ src/condition/SimpleConditionTracker.cpp \
+ src/condition/CombinationConditionTracker.cpp \
+ src/matchers/SimpleLogMatchingTracker.cpp \
+ src/matchers/CombinationLogMatchingTracker.cpp \
+ src/metrics/metrics_manager_util.cpp \
+ src/metrics/CountMetricProducer.cpp \
+ src/metrics/CountAnomalyTracker.cpp \
+ src/condition/condition_util.cpp \
+ src/UidMap.cpp \
+ $(call all-cpp-files-under, tests) \
LOCAL_STATIC_LIBRARIES := \
libgmock \
diff --git a/core/tests/coretests/src/android/print/PrintTestActivity.java b/cmds/statsd/src/PackageInfoListener.h
index e9b001f3c821..476c1d953cbc 100644
--- a/core/tests/coretests/src/android/print/PrintTestActivity.java
+++ b/cmds/statsd/src/PackageInfoListener.h
@@ -14,19 +14,25 @@
* limitations under the License.
*/
-package android.print;
+#ifndef STATSD_PACKAGE_INFO_LISTENER_H
+#define STATSD_PACKAGE_INFO_LISTENER_H
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.WindowManager;
+#include <utils/RefBase.h>
+#include <string>
-public class PrintTestActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+namespace android {
+namespace os {
+namespace statsd {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
- }
-}
+class PackageInfoListener : public virtual android::RefBase {
+public:
+ // Uid map will notify this listener that the app with apk name and uid has been upgraded to
+ // the specified version.
+ virtual void notifyAppUpgrade(const std::string& apk, const int uid, const int version) = 0;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif //STATSD_PACKAGE_INFO_LISTENER_H
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 117fb5e2cefc..f877ef30432c 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -20,7 +20,6 @@
#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
#include <log/log_event_list.h>
#include <metrics/CountMetricProducer.h>
-#include <parse_util.h>
#include <utils/Errors.h>
using namespace android;
@@ -32,7 +31,9 @@ namespace android {
namespace os {
namespace statsd {
-StatsLogProcessor::StatsLogProcessor() : m_dropbox_writer("all-logs") {
+StatsLogProcessor::StatsLogProcessor(const sp<UidMap> &uidMap)
+ : m_dropbox_writer("all-logs"), m_UidMap(uidMap)
+{
// hardcoded config
// this should be called from StatsService when it receives a statsd_config
UpdateConfig(0, buildFakeConfig());
@@ -41,28 +42,6 @@ StatsLogProcessor::StatsLogProcessor() : m_dropbox_writer("all-logs") {
StatsLogProcessor::~StatsLogProcessor() {
}
-StatsdConfig StatsLogProcessor::buildFakeConfig() {
- // HACK: Hard code a test metric for counting screen on events...
- StatsdConfig config;
- config.set_config_id(12345L);
-
- CountMetric* metric = config.add_count_metric();
- metric->set_metric_id(20150717L);
- metric->set_what("SCREEN_IS_ON");
- metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
-
- LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
- eventMatcher->set_name("SCREEN_IS_ON");
-
- SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
- simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()
- ->set_key(1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleLogEntryMatcher->mutable_key_value_matcher(0)
- ->set_eq_int(2/*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
- return config;
-}
-
// TODO: what if statsd service restarts? How do we know what logs are already processed before?
void StatsLogProcessor::OnLogEvent(const log_msg& msg) {
// TODO: Use EventMetric to filter the events we want to log.
@@ -83,7 +62,14 @@ void StatsLogProcessor::UpdateConfig(const int config_source, const StatsdConfig
ALOGD("Updated configuration for source %i", config_source);
- mMetricsManagers.insert({config_source, std::make_unique<MetricsManager>(config)});
+ unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(config);
+ if (newMetricsManager->isConfigValid()) {
+ mMetricsManagers.insert({config_source, std::move(newMetricsManager)});
+ ALOGD("StatsdConfig valid");
+ } else {
+ // If there is any error in the config, don't use it.
+ ALOGD("StatsdConfig NOT valid");
+ }
}
} // namespace statsd
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 88c63fa5a149..05e441caa496 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -16,11 +16,12 @@
#ifndef STATS_LOG_PROCESSOR_H
#define STATS_LOG_PROCESSOR_H
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "DropboxWriter.h"
#include "LogReader.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "metrics/MetricsManager.h"
-#include "parse_util.h"
+#include "stats_util.h"
+#include "UidMap.h"
#include <log/logprint.h>
#include <stdio.h>
@@ -32,7 +33,7 @@ namespace statsd {
class StatsLogProcessor : public LogListener {
public:
- StatsLogProcessor();
+ StatsLogProcessor(const sp<UidMap> &uidMap);
virtual ~StatsLogProcessor();
virtual void OnLogEvent(const log_msg& msg);
@@ -45,7 +46,7 @@ private:
std::unordered_map<int, std::unique_ptr<MetricsManager>> mMetricsManagers;
- static StatsdConfig buildFakeConfig();
+ sp<UidMap> m_UidMap; // Reference to the UidMap to lookup app name and version for each uid.
};
} // namespace statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 9baeebbd554f..b496404962d5 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -40,7 +40,8 @@ namespace os {
namespace statsd {
StatsService::StatsService(const sp<Looper>& handlerLooper)
- : mAnomalyMonitor(new AnomalyMonitor(2)), mStatsPullerManager() // TODO: Change this based on the config
+ : mAnomalyMonitor(new AnomalyMonitor(2)),m_UidMap(new UidMap()), mStatsPullerManager()
+ // TODO: Change AnomalyMonitor initialization based on the config
{
ALOGD("stats service constructed");
}
@@ -131,6 +132,9 @@ status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>&
if (!args[0].compare(String8("config"))) {
return doLoadConfig(in);
}
+ if (!args[0].compare(String8("print-uid-map"))) {
+ return doPrintUidMap(out);
+ }
}
printCmdHelp(out);
@@ -153,6 +157,43 @@ status_t StatsService::doLoadConfig(FILE* in) {
}
}
+Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
+ const vector<String16>& app) {
+ if (DEBUG) ALOGD("StatsService::informAllUidData was called");
+
+ if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "Only system uid can call informAllUidData");
+ }
+
+ m_UidMap->updateMap(uid, version, app);
+ if (DEBUG) ALOGD("StatsService::informAllUidData succeeded");
+
+ return Status::ok();
+}
+
+Status StatsService::informOnePackage(const String16& app, int32_t uid, int32_t version) {
+ if (DEBUG) ALOGD("StatsService::informOnePackage was called");
+
+ if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "Only system uid can call informOnePackage");
+ }
+ m_UidMap->updateApp(app, uid, version);
+ return Status::ok();
+}
+
+Status StatsService::informOnePackageRemoved(const String16& app, int32_t uid) {
+ if (DEBUG) ALOGD("StatsService::informOnePackageRemoved was called");
+
+ if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "Only system uid can call informOnePackageRemoved");
+ }
+ m_UidMap->removeApp(app, uid);
+ return Status::ok();
+}
+
Status StatsService::informAnomalyAlarmFired() {
if (DEBUG) ALOGD("StatsService::informAnomalyAlarmFired was called");
@@ -261,9 +302,15 @@ status_t StatsService::doPrintStatsLog(FILE* out, const Vector<String8>& args) {
return DropboxReader::readStatsLogs(out, args[1].string(), msec);
}
+status_t StatsService::doPrintUidMap(FILE* out) {
+ m_UidMap->printUidMap(out);
+ return NO_ERROR;
+}
+
void StatsService::printCmdHelp(FILE* out) {
fprintf(out, "Usage:\n");
fprintf(out, "\t print-stats-log [tag_required] [timestamp_nsec_optional]\n");
+ fprintf(out, "\t print-uid-map Prints the UID, app name, version mapping.\n");
fprintf(out,
"\t config\t Loads a new config from command-line (must be proto in wire-encoded "
"format).\n");
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 964227975fe8..541f7e8be7fa 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -20,6 +20,8 @@
#include "AnomalyMonitor.h"
#include "StatsLogProcessor.h"
#include "StatsPullerManager.h"
+#include "StatsPuller.h"
+#include "UidMap.h"
#include <android/os/BnStatsManager.h>
#include <android/os/IStatsCompanionService.h>
@@ -60,6 +62,11 @@ public:
virtual Status informPollAlarmFired();
+ virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
+ const vector<String16>& app);
+ virtual Status informOnePackage(const String16& app, int32_t uid, int32_t version);
+ virtual Status informOnePackageRemoved(const String16& app, int32_t uid);
+
virtual status_t setProcessor(const sp<StatsLogProcessor>& main_processor);
// TODO: public for testing since statsd doesn't run when system starts. Change to private
@@ -71,10 +78,16 @@ public:
// TODO: Should be private. Temporarily public for testing purposes only.
const sp<AnomalyMonitor> mAnomalyMonitor;
+ sp<UidMap> getUidMap() {
+ return m_UidMap;
+ }
+
/** Fetches and returns the StatsCompanionService. */
static sp<IStatsCompanionService> getStatsCompanionService();
private:
+ sp<UidMap> m_UidMap; // Reference to the UID map needed for translating UID to app name/version.
+
sp<StatsLogProcessor> m_processor; // Reference to the processor for updating configs.
status_t doPrintStatsLog(FILE* out, const Vector<String8>& args);
@@ -84,6 +97,8 @@ private:
status_t doLoadConfig(FILE* in);
StatsPullerManager mStatsPullerManager;
+
+ status_t doPrintUidMap(FILE* out);
};
// --- StatsdDeathRecipient ---
diff --git a/cmds/statsd/src/UidMap.cpp b/cmds/statsd/src/UidMap.cpp
new file mode 100644
index 000000000000..76a7f3f28dee
--- /dev/null
+++ b/cmds/statsd/src/UidMap.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, versionCode 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 "UidMap.h"
+#include <cutils/log.h>
+#include <utils/Errors.h>
+
+using namespace android;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+bool UidMap::hasApp(int uid, const string& packageName) const {
+ lock_guard<mutex> lock(mMutex);
+
+ auto range = mMap.equal_range(uid);
+ for (auto it = range.first; it != range.second; ++it) {
+ if (it->second.packageName == packageName) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int UidMap::getAppVersion(int uid, const string& packageName) const {
+ lock_guard<mutex> lock(mMutex);
+
+ auto range = mMap.equal_range(uid);
+ for (auto it = range.first; it != range.second; ++it) {
+ if (it->second.packageName == packageName) {
+ return it->second.versionCode;
+ }
+ }
+ return 0;
+}
+
+void UidMap::updateMap(const vector <int32_t> &uid, const vector <int32_t> &versionCode,
+ const vector <String16> &packageName) {
+ lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
+
+ mMap.clear();
+ for (unsigned long j=0; j<uid.size(); j++) {
+ mMap.insert(make_pair(uid[j], AppData(string(String8(packageName[j]).string()),
+ versionCode[j])));
+ }
+
+ if (mOutput.initial_size() == 0) { // Provide the initial states in the mOutput proto
+ for (unsigned long j=0; j<uid.size(); j++) {
+ auto t = mOutput.add_initial();
+ t->set_app(string(String8(packageName[j]).string()));
+ t->set_version(int(versionCode[j]));
+ t->set_uid(uid[j]);
+ }
+ }
+}
+
+void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode){
+ lock_guard<mutex> lock(mMutex);
+
+ string app = string(String8(app_16).string());
+
+ // Notify any interested producers that this app has updated
+ for (auto it : mSubscribers) {
+ it->notifyAppUpgrade(app, uid, versionCode);
+ }
+
+ auto log = mOutput.add_changes();
+ log->set_deletion(false);
+ //log.timestamp = TODO: choose how timestamps are computed
+ log->set_app(app);
+ log->set_uid(uid);
+ log->set_version(versionCode);
+
+ auto range = mMap.equal_range(int(uid));
+ for (auto it = range.first; it != range.second; ++it) {
+ if (it->second.packageName == app) {
+ it->second.versionCode = int(versionCode);
+ return;
+ }
+ ALOGD("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid);
+ return;
+ }
+
+ // Otherwise, we need to add an app at this uid.
+ mMap.insert(make_pair(uid, AppData(app, int(versionCode))));
+}
+
+
+void UidMap::removeApp(const String16& app_16, const int32_t& uid){
+ lock_guard<mutex> lock(mMutex);
+
+ string app = string(String8(app_16).string());
+
+ auto log = mOutput.add_changes();
+ log->set_deletion(true);
+ //log.timestamp = TODO: choose how timestamps are computed
+ log->set_app(app);
+ log->set_uid(uid);
+
+ auto range = mMap.equal_range(int(uid));
+ for (auto it = range.first; it != range.second; ++it) {
+ if (it->second.packageName == app) {
+ mMap.erase(it);
+ return;
+ }
+ }
+ ALOGD("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid);
+ return;
+}
+
+void UidMap::addListener(sp<PackageInfoListener> producer) {
+ lock_guard<mutex> lock(mMutex); // Lock for updates
+ mSubscribers.insert(producer);
+}
+
+void UidMap::removeListener(sp<PackageInfoListener> producer) {
+ lock_guard<mutex> lock(mMutex); // Lock for updates
+ mSubscribers.erase(producer);
+}
+
+UidMapping UidMap::getAndClearOutput() {
+ lock_guard<mutex> lock(mMutex); // Lock for updates
+
+ auto ret = UidMapping(mOutput); // Copy that will be returned.
+ mOutput.Clear();
+
+ // Re-initialize the initial state for the outputs. This results in extra data being uploaded
+ // but helps ensure we can't re-construct the UID->app name, versionCode mapping in server.
+ for (auto it : mMap) {
+ auto t = mOutput.add_initial();
+ t->set_app(it.second.packageName);
+ t->set_version(it.second.versionCode);
+ t->set_uid(it.first);
+ }
+
+ return ret;
+}
+
+void UidMap::printUidMap(FILE* out) {
+ lock_guard<mutex> lock(mMutex);
+
+ for (auto it : mMap) {
+ fprintf(out, "%s, v%d (%i)\n", it.second.packageName.c_str(), it.second.versionCode, it.first);
+ }
+}
+
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/UidMap.h b/cmds/statsd/src/UidMap.h
new file mode 100644
index 000000000000..1481010a60b8
--- /dev/null
+++ b/cmds/statsd/src/UidMap.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 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 STATSD_UIDMAP_H
+#define STATSD_UIDMAP_H
+
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "PackageInfoListener.h"
+
+#include <binder/IResultReceiver.h>
+#include <binder/IShellCallback.h>
+#include <log/logprint.h>
+#include <mutex>
+#include <string>
+#include <stdio.h>
+#include <set>
+#include <unordered_map>
+#include <utils/RefBase.h>
+
+using namespace std;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+struct AppData {
+ const string packageName;
+ int versionCode;
+
+ AppData(const string& a, const int v) : packageName(a), versionCode(v) {};
+};
+
+// UidMap keeps track of what the corresponding app name (APK name) and version code for every uid
+// at any given moment. This map must be updated by StatsCompanionService.
+class UidMap : public virtual android::RefBase {
+public:
+ /*
+ * All three inputs must be the same size, and the jth element in each array refers to the same
+ * tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
+ */
+ void updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
+ const vector<String16>& packageName);
+
+ // Returns true if the given uid contains the specified app (eg. com.google.android.gms).
+ bool hasApp(int uid, const string& packageName) const;
+
+ int getAppVersion(int uid, const string& packageName) const;
+
+ void updateApp(const String16& packageName, const int32_t& uid, const int32_t& versionCode);
+ void removeApp(const String16& packageName, const int32_t& uid);
+
+ // Helper for debugging contents of this uid map. Can be triggered with:
+ // adb shell cmd stats print-uid-map
+ void printUidMap(FILE* out);
+
+ // Commands for indicating to the map that a producer should be notified if an app is updated.
+ // This allows the metric producer to distinguish when the same uid or app represents a
+ // different version of an app.
+ void addListener(sp<PackageInfoListener> producer);
+ // Remove the listener from the set of metric producers that subscribe to updates.
+ void removeListener(sp<PackageInfoListener> producer);
+
+ // Grabs the current output contents and then clears it.
+ UidMapping getAndClearOutput();
+
+private:
+ // TODO: Use shared_mutex for improved read-locking if a library can be found in Android.
+ mutable mutex mMutex;
+
+ std::unordered_multimap<int, AppData> mMap;
+
+ // We prepare the output proto as apps are updated, so that we can grab the current output.
+ UidMapping mOutput;
+
+ // Metric producers that should be notified if there's an upgrade in any app.
+ set<sp<PackageInfoListener>> mSubscribers;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif //STATSD_UIDMAP_H
+
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
new file mode 100644
index 000000000000..6188383d4e8d
--- /dev/null
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "CombinationConditionTracker"
+#define DEBUG true // STOPSHIP if true
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "CombinationConditionTracker.h"
+#include <cutils/log.h>
+#include <log/logprint.h>
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+CombinationConditionTracker::CombinationConditionTracker(const string& name, const int index)
+ : ConditionTracker(name, index) {
+ VLOG("creating CombinationConditionTracker %s", mName.c_str());
+}
+
+CombinationConditionTracker::~CombinationConditionTracker() {
+ VLOG("~CombinationConditionTracker() %s", mName.c_str());
+}
+
+bool CombinationConditionTracker::init(const vector<Condition>& allConditionConfig,
+ const vector<sp<ConditionTracker>>& allConditionTrackers,
+ const unordered_map<string, int>& conditionNameIndexMap,
+ vector<bool>& stack) {
+ VLOG("Combiniation condition init() %s", mName.c_str());
+ if (mInitialized) {
+ return true;
+ }
+
+ // mark this node as visited in the recursion stack.
+ stack[mIndex] = true;
+
+ Condition_Combination combinationCondition = allConditionConfig[mIndex].combination();
+
+ if (!combinationCondition.has_operation()) {
+ return false;
+ }
+ mLogicalOperation = combinationCondition.operation();
+
+ if (mLogicalOperation == LogicalOperation::NOT && combinationCondition.condition_size() != 1) {
+ return false;
+ }
+
+ for (string child : combinationCondition.condition()) {
+ auto it = conditionNameIndexMap.find(child);
+
+ if (it == conditionNameIndexMap.end()) {
+ ALOGW("Condition %s not found in the config", child.c_str());
+ return false;
+ }
+
+ int childIndex = it->second;
+ const auto& childTracker = allConditionTrackers[childIndex];
+ // if the child is a visited node in the recursion -> circle detected.
+ if (stack[childIndex]) {
+ ALOGW("Circle detected!!!");
+ return false;
+ }
+
+ bool initChildSucceeded = childTracker->init(allConditionConfig, allConditionTrackers,
+ conditionNameIndexMap, stack);
+
+ if (!initChildSucceeded) {
+ ALOGW("Child initialization failed %s ", child.c_str());
+ return false;
+ } else {
+ ALOGW("Child initialization success %s ", child.c_str());
+ }
+
+ mChildren.push_back(childIndex);
+
+ mTrackerIndex.insert(childTracker->getLogTrackerIndex().begin(),
+ childTracker->getLogTrackerIndex().end());
+ }
+
+ // unmark this node in the recursion stack.
+ stack[mIndex] = false;
+
+ mInitialized = true;
+
+ return true;
+}
+
+bool CombinationConditionTracker::evaluateCondition(
+ const LogEventWrapper& event, const std::vector<MatchingState>& eventMatcherValues,
+ const std::vector<sp<ConditionTracker>>& mAllConditions,
+ std::vector<ConditionState>& conditionCache, std::vector<bool>& changedCache) {
+ // value is up to date.
+ if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
+ return false;
+ }
+
+ for (const int childIndex : mChildren) {
+ if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
+ const sp<ConditionTracker>& child = mAllConditions[childIndex];
+ child->evaluateCondition(event, eventMatcherValues, mAllConditions, conditionCache,
+ changedCache);
+ }
+ }
+
+ ConditionState newCondition =
+ evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
+
+ bool changed = (mConditionState != newCondition);
+ mConditionState = newCondition;
+
+ conditionCache[mIndex] = mConditionState;
+
+ changedCache[mIndex] = changed;
+ return changed;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
new file mode 100644
index 000000000000..38780e7062ed
--- /dev/null
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#ifndef COMBINATION_CONDITION_TRACKER_H
+#define COMBINATION_CONDITION_TRACKER_H
+
+#include "ConditionTracker.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class CombinationConditionTracker : public virtual ConditionTracker {
+public:
+ CombinationConditionTracker(const std::string& name, const int index);
+
+ ~CombinationConditionTracker();
+
+ bool init(const std::vector<Condition>& allConditionConfig,
+ const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ const std::unordered_map<std::string, int>& conditionNameIndexMap,
+ std::vector<bool>& stack) override;
+
+ bool evaluateCondition(const LogEventWrapper& event,
+ const std::vector<MatchingState>& eventMatcherValues,
+ const std::vector<sp<ConditionTracker>>& mAllConditions,
+ std::vector<ConditionState>& conditionCache,
+ std::vector<bool>& changedCache) override;
+
+private:
+ LogicalOperation mLogicalOperation;
+ // Store index of the children Conditions.
+ // We don't store string name of the Children, because we want to get rid of the hash map to
+ // map the name to object. We don't want to store smart pointers to children, because it
+ // increases the risk of circular dependency and memory leak.
+ std::vector<int> mChildren;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // COMBINATION_CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
new file mode 100644
index 000000000000..2da8fa0e8655
--- /dev/null
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#ifndef CONDITION_TRACKER_H
+#define CONDITION_TRACKER_H
+
+#include <cutils/log.h>
+#include <log/logprint.h>
+#include <utils/RefBase.h>
+#include <unordered_map>
+#include "../matchers/LogMatchingTracker.h"
+#include "../matchers/matcher_util.h"
+#include "condition_util.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class ConditionTracker : public virtual RefBase {
+public:
+ ConditionTracker(const std::string& name, const int index)
+ : mName(name),
+ mIndex(index),
+ mInitialized(false),
+ mConditionState(ConditionState::kUnknown),
+ mTrackerIndex(){};
+
+ virtual ~ConditionTracker(){};
+
+ // Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
+ // be done in the constructor, but we do it separately because (1) easy to return a bool to
+ // indicate whether the initialization is successful. (2) makes unit test easier.
+ // allConditionConfig: the list of all Condition config from statsd_config.
+ // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
+ // need to call init() on children conditions)
+ // conditionNameIndexMap: the mapping from condition name to its index.
+ // stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
+ virtual bool init(const std::vector<Condition>& allConditionConfig,
+ const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ const std::unordered_map<std::string, int>& conditionNameIndexMap,
+ std::vector<bool>& stack) = 0;
+
+ // evaluate current condition given the new event.
+ // return true if the condition state changed, false if the condition state is not changed.
+ // event: the new log event
+ // eventMatcherValues: the results of the LogMatcherTrackers. LogMatcherTrackers always process
+ // event before ConditionTrackers, because ConditionTracker depends on
+ // LogMatchingTrackers.
+ // mAllConditions: the list of all ConditionTracker
+ // conditionCache: the cached results of the ConditionTrackers for this new event.
+ // changedCache: the bit map to record whether the condition has changed.
+ virtual bool evaluateCondition(const LogEventWrapper& event,
+ const std::vector<MatchingState>& eventMatcherValues,
+ const std::vector<sp<ConditionTracker>>& mAllConditions,
+ std::vector<ConditionState>& conditionCache,
+ std::vector<bool>& changedCache) = 0;
+
+ // Return the current condition state.
+ virtual ConditionState isConditionMet() {
+ ALOGW("Condition %s value %d", mName.c_str(), mConditionState);
+ return mConditionState;
+ };
+
+ // return the list of LogMatchingTracker index that this ConditionTracker uses.
+ virtual const std::set<int>& getLogTrackerIndex() const {
+ return mTrackerIndex;
+ }
+
+protected:
+ // We don't really need the string name, but having a name here makes log messages
+ // easy to debug.
+ const std::string mName;
+
+ // the index of this condition in the manager's condition list.
+ const int mIndex;
+
+ // if it's properly initialized.
+ bool mInitialized;
+
+ // current condition state.
+ ConditionState mConditionState;
+
+ // the list of LogMatchingTracker index that this ConditionTracker uses.
+ std::set<int> mTrackerIndex;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
new file mode 100644
index 000000000000..e78c0de7bdf5
--- /dev/null
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Stats_SimpleConditionTracker"
+#define DEBUG true // STOPSHIP if true
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "SimpleConditionTracker.h"
+#include <cutils/log.h>
+#include <log/logprint.h>
+
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+SimpleConditionTracker::SimpleConditionTracker(
+ const string& name, const int index, const SimpleCondition& simpleCondition,
+ const unordered_map<string, int>& trackerNameIndexMap)
+ : ConditionTracker(name, index) {
+ VLOG("creating SimpleConditionTracker %s", mName.c_str());
+ mCountNesting = simpleCondition.count_nesting();
+
+ if (simpleCondition.has_start()) {
+ auto pair = trackerNameIndexMap.find(simpleCondition.start());
+ if (pair == trackerNameIndexMap.end()) {
+ ALOGW("Start matcher %s not found in the config", simpleCondition.start().c_str());
+ return;
+ }
+ mStartLogMatcherIndex = pair->second;
+ mTrackerIndex.insert(mStartLogMatcherIndex);
+ } else {
+ mStartLogMatcherIndex = -1;
+ }
+
+ if (simpleCondition.has_stop()) {
+ auto pair = trackerNameIndexMap.find(simpleCondition.stop());
+ if (pair == trackerNameIndexMap.end()) {
+ ALOGW("Stop matcher %s not found in the config", simpleCondition.stop().c_str());
+ return;
+ }
+ mStopLogMatcherIndex = pair->second;
+ mTrackerIndex.insert(mStopLogMatcherIndex);
+ } else {
+ mStopLogMatcherIndex = -1;
+ }
+
+ if (simpleCondition.has_stop_all()) {
+ auto pair = trackerNameIndexMap.find(simpleCondition.stop_all());
+ if (pair == trackerNameIndexMap.end()) {
+ ALOGW("Stop matcher %s not found in the config", simpleCondition.stop().c_str());
+ return;
+ }
+ mStopAllLogMatcherIndex = pair->second;
+ mTrackerIndex.insert(mStopAllLogMatcherIndex);
+ } else {
+ mStopAllLogMatcherIndex = -1;
+ }
+
+ mInitialized = true;
+}
+
+SimpleConditionTracker::~SimpleConditionTracker() {
+ VLOG("~SimpleConditionTracker()");
+}
+
+bool SimpleConditionTracker::init(const vector<Condition>& allConditionConfig,
+ const vector<sp<ConditionTracker>>& allConditionTrackers,
+ const unordered_map<string, int>& conditionNameIndexMap,
+ vector<bool>& stack) {
+ // SimpleConditionTracker does not have dependency on other conditions, thus we just return
+ // if the initialization was successful.
+ return mInitialized;
+}
+
+bool SimpleConditionTracker::evaluateCondition(const LogEventWrapper& event,
+ const vector<MatchingState>& eventMatcherValues,
+ const vector<sp<ConditionTracker>>& mAllConditions,
+ vector<ConditionState>& conditionCache,
+ vector<bool>& changedCache) {
+ if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
+ // it has been evaluated.
+ VLOG("Yes, already evaluated, %s %d", mName.c_str(), mConditionState);
+ return false;
+ }
+
+ // Ignore nesting, because we know we cannot trust ourselves on tracking nesting conditions.
+ ConditionState newCondition = mConditionState;
+ // Note: The order to evaluate the following start, stop, stop_all matters.
+ // The priority of overwrite is stop_all > stop > start.
+ if (mStartLogMatcherIndex >= 0 &&
+ eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) {
+ newCondition = ConditionState::kTrue;
+ }
+
+ if (mStopLogMatcherIndex >= 0 &&
+ eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) {
+ newCondition = ConditionState::kFalse;
+ }
+
+ if (mStopAllLogMatcherIndex >= 0 &&
+ eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) {
+ newCondition = ConditionState::kFalse;
+ }
+
+ bool changed = (mConditionState != newCondition);
+ mConditionState = newCondition;
+ conditionCache[mIndex] = mConditionState;
+ changedCache[mIndex] = changed;
+ return changed;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
new file mode 100644
index 000000000000..41e17076cbdc
--- /dev/null
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef SIMPLE_CONDITION_TRACKER_H
+#define SIMPLE_CONDITION_TRACKER_H
+
+#include "ConditionTracker.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class SimpleConditionTracker : public virtual ConditionTracker {
+public:
+ SimpleConditionTracker(const std::string& name, const int index,
+ const SimpleCondition& simpleCondition,
+ const std::unordered_map<std::string, int>& trackerNameIndexMap);
+
+ ~SimpleConditionTracker();
+
+ bool init(const std::vector<Condition>& allConditionConfig,
+ const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ const std::unordered_map<std::string, int>& conditionNameIndexMap,
+ std::vector<bool>& stack) override;
+
+ bool evaluateCondition(const LogEventWrapper& event,
+ const std::vector<MatchingState>& eventMatcherValues,
+ const std::vector<sp<ConditionTracker>>& mAllConditions,
+ std::vector<ConditionState>& conditionCache,
+ std::vector<bool>& changedCache) override;
+
+private:
+ // The index of the LogEventMatcher which defines the start.
+ int mStartLogMatcherIndex;
+
+ // The index of the LogEventMatcher which defines the end.
+ int mStopLogMatcherIndex;
+
+ // if the start end needs to be nested.
+ bool mCountNesting;
+
+ // The index of the LogEventMatcher which defines the stop all.
+ int mStopAllLogMatcherIndex;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // SIMPLE_CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
new file mode 100644
index 000000000000..cb07d1530dab
--- /dev/null
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 "condition_util.h"
+
+#include <cutils/log.h>
+#include <log/event_tag_map.h>
+#include <log/log_event_list.h>
+#include <log/logprint.h>
+#include <utils/Errors.h>
+#include <unordered_map>
+#include "ConditionTracker.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "stats_util.h"
+
+using std::set;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+ConditionState evaluateCombinationCondition(const std::vector<int>& children,
+ const LogicalOperation& operation,
+ const std::vector<ConditionState>& conditionCache) {
+ ConditionState newCondition;
+
+ bool hasUnknown = false;
+ bool hasFalse = false;
+ bool hasTrue = false;
+
+ for (auto childIndex : children) {
+ ConditionState childState = conditionCache[childIndex];
+ if (childState == ConditionState::kUnknown) {
+ hasUnknown = true;
+ break;
+ }
+ if (childState == ConditionState::kFalse) {
+ hasFalse = true;
+ }
+ if (childState == ConditionState::kTrue) {
+ hasTrue = true;
+ }
+ }
+
+ // If any child condition is in unknown state, the condition is unknown too.
+ if (hasUnknown) {
+ return ConditionState::kUnknown;
+ }
+
+ switch (operation) {
+ case LogicalOperation::AND: {
+ newCondition = hasFalse ? ConditionState::kFalse : ConditionState::kTrue;
+ break;
+ }
+ case LogicalOperation::OR: {
+ newCondition = hasTrue ? ConditionState::kTrue : ConditionState::kFalse;
+ break;
+ }
+ case LogicalOperation::NOT:
+ newCondition = (conditionCache[children[0]] == ConditionState::kFalse)
+ ? ConditionState::kTrue
+ : ConditionState::kFalse;
+ break;
+ case LogicalOperation::NAND:
+ newCondition = hasFalse ? ConditionState::kTrue : ConditionState::kFalse;
+ break;
+ case LogicalOperation::NOR:
+ newCondition = hasTrue ? ConditionState::kFalse : ConditionState::kTrue;
+ break;
+ }
+ return newCondition;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/ConditionTracker.h b/cmds/statsd/src/condition/condition_util.h
index b94d5abc2cf5..a4fcea38d6b5 100644
--- a/cmds/statsd/src/metrics/ConditionTracker.h
+++ b/cmds/statsd/src/condition/condition_util.h
@@ -14,38 +14,28 @@
* limitations under the License.
*/
-#ifndef CONDITION_TRACKER_H
-#define CONDITION_TRACKER_H
+#ifndef CONDITION_UTIL_H
+#define CONDITION_UTIL_H
-#include <utils/RefBase.h>
-#include "../matchers/LogEntryMatcherManager.h"
+#include <vector>
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
namespace android {
namespace os {
namespace statsd {
-class ConditionTracker : public RefBase {
-public:
- ConditionTracker();
-
- ConditionTracker(const Condition& condition);
-
- ~ConditionTracker();
-
- void evaluateCondition(const LogEventWrapper& event);
-
- bool isConditionMet() const;
-
-private:
- // this is the definition of the Condition.
- Condition mCondition;
-
- bool mIsConditionMet;
+enum ConditionState {
+ kNotEvaluated = -2,
+ kUnknown = -1,
+ kFalse = 0,
+ kTrue = 1,
};
+ConditionState evaluateCombinationCondition(const std::vector<int>& children,
+ const LogicalOperation& operation,
+ const std::vector<ConditionState>& conditionCache);
} // namespace statsd
} // namespace os
} // namespace android
-
-#endif // CONDITION_TRACKER_H
+#endif // CONDITION_UTIL_H
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index b303321d8ef2..37477dc50e4e 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -20,6 +20,7 @@
#include "LogReader.h"
#include "StatsLogProcessor.h"
#include "StatsService.h"
+#include "UidMap.h"
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
@@ -56,7 +57,7 @@ static void* log_reader_thread_func(void* cookie) {
// Put the printer one first, so it will print before the real ones.
reader->AddListener(new LogEntryPrinter(STDOUT_FILENO));
- sp<StatsLogProcessor> main_processor = new StatsLogProcessor();
+ sp<StatsLogProcessor> main_processor = new StatsLogProcessor(data->service->getUidMap());
data->service->setProcessor(main_processor);
reader->AddListener(main_processor);
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
new file mode 100644
index 000000000000..9f9b648ae1a5
--- /dev/null
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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 "CombinationLogMatchingTracker.h"
+
+#include <cutils/log.h>
+#include "matcher_util.h"
+using std::set;
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+CombinationLogMatchingTracker::CombinationLogMatchingTracker(const string& name, const int index)
+ : LogMatchingTracker(name, index) {
+}
+
+CombinationLogMatchingTracker::~CombinationLogMatchingTracker() {
+}
+
+bool CombinationLogMatchingTracker::init(const vector<LogEntryMatcher>& allLogMatchers,
+ const vector<sp<LogMatchingTracker>>& allTrackers,
+ const unordered_map<string, int>& matcherMap,
+ vector<bool>& stack) {
+ if (mInitialized) {
+ return true;
+ }
+
+ // mark this node as visited in the recursion stack.
+ stack[mIndex] = true;
+
+ LogEntryMatcher_Combination matcher = allLogMatchers[mIndex].combination();
+
+ // LogicalOperation is missing in the config
+ if (!matcher.has_operation()) {
+ return false;
+ }
+
+ mLogicalOperation = matcher.operation();
+
+ if (mLogicalOperation == LogicalOperation::NOT && matcher.matcher_size() != 1) {
+ return false;
+ }
+
+ for (const string& child : matcher.matcher()) {
+ auto pair = matcherMap.find(child);
+ if (pair == matcherMap.end()) {
+ ALOGW("Matcher %s not found in the config", child.c_str());
+ return false;
+ }
+
+ int childIndex = pair->second;
+
+ // if the child is a visited node in the recursion -> circle detected.
+ if (stack[childIndex]) {
+ ALOGE("Circle detected in matcher config");
+ return false;
+ }
+
+ if (!allTrackers[childIndex]->init(allLogMatchers, allTrackers, matcherMap, stack)) {
+ ALOGW("child matcher init failed %s", child.c_str());
+ return false;
+ }
+
+ mChildren.push_back(childIndex);
+
+ const set<int>& childTagIds = allTrackers[childIndex]->getTagIds();
+ mTagIds.insert(childTagIds.begin(), childTagIds.end());
+ }
+
+ mInitialized = true;
+ // unmark this node in the recursion stack.
+ stack[mIndex] = false;
+ return true;
+}
+
+void CombinationLogMatchingTracker::onLogEvent(const LogEventWrapper& event,
+ const vector<sp<LogMatchingTracker>>& allTrackers,
+ vector<MatchingState>& matcherResults) {
+ // this event has been processed.
+ if (matcherResults[mIndex] != MatchingState::kNotComputed) {
+ return;
+ }
+
+ if (mTagIds.find(event.tagId) == mTagIds.end()) {
+ matcherResults[mIndex] = MatchingState::kNotMatched;
+ return;
+ }
+
+ // evaluate children matchers if they haven't been evaluated.
+ for (const int childIndex : mChildren) {
+ if (matcherResults[childIndex] == MatchingState::kNotComputed) {
+ const sp<LogMatchingTracker>& child = allTrackers[childIndex];
+ child->onLogEvent(event, allTrackers, matcherResults);
+ }
+ }
+
+ bool matched = combinationMatch(mChildren, mLogicalOperation, matcherResults);
+ matcherResults[mIndex] = matched ? MatchingState::kMatched : MatchingState::kNotMatched;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
new file mode 100644
index 000000000000..51ee2328ee19
--- /dev/null
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+#ifndef COMBINATION_LOG_MATCHING_TRACKER_H
+#define COMBINATION_LOG_MATCHING_TRACKER_H
+
+#include <log/log_read.h>
+#include <log/logprint.h>
+#include <set>
+#include <unordered_map>
+#include <vector>
+#include "LogMatchingTracker.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Represents a LogEntryMatcher_Combination in the StatsdConfig.
+class CombinationLogMatchingTracker : public virtual LogMatchingTracker {
+public:
+ CombinationLogMatchingTracker(const std::string& name, const int index);
+
+ bool init(const std::vector<LogEntryMatcher>& allLogMatchers,
+ const std::vector<sp<LogMatchingTracker>>& allTrackers,
+ const std::unordered_map<std::string, int>& matcherMap,
+ std::vector<bool>& stack);
+
+ ~CombinationLogMatchingTracker();
+
+ void onLogEvent(const LogEventWrapper& event,
+ const std::vector<sp<LogMatchingTracker>>& allTrackers,
+ std::vector<MatchingState>& matcherResults) override;
+
+private:
+ LogicalOperation mLogicalOperation;
+
+ std::vector<int> mChildren;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#endif // COMBINATION_LOG_MATCHING_TRACKER_H
diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h
new file mode 100644
index 000000000000..4244bd597b46
--- /dev/null
+++ b/cmds/statsd/src/matchers/LogMatchingTracker.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#ifndef LOG_MATCHING_TRACKER_H
+#define LOG_MATCHING_TRACKER_H
+
+#include <log/log_read.h>
+#include <log/logprint.h>
+#include <utils/RefBase.h>
+#include <set>
+#include <unordered_map>
+
+#include <vector>
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matcher_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class LogMatchingTracker : public virtual RefBase {
+public:
+ LogMatchingTracker(const std::string& name, const int index)
+ : mName(name), mIndex(index), mInitialized(false){};
+
+ virtual ~LogMatchingTracker(){};
+
+ // Initialize this LogMatchingTracker.
+ // allLogMatchers: the list of the LogEntryMatcher proto config. This is needed because we don't
+ // store the proto object in memory. We only need it during initilization.
+ // allTrackers: the list of the LogMatchingTracker objects. It's a one-to-one mapping with
+ // allLogMatchers. This is needed because the initialization is done recursively
+ // for CombinationLogMatchingTrackers using DFS.
+ // stack: a bit map to record which matcher has been visited on the stack. This is for detecting
+ // circle dependency.
+ virtual bool init(const std::vector<LogEntryMatcher>& allLogMatchers,
+ const std::vector<sp<LogMatchingTracker>>& allTrackers,
+ const std::unordered_map<std::string, int>& matcherMap,
+ std::vector<bool>& stack) = 0;
+
+ // Called when a log event comes.
+ // event: the log event.
+ // allTrackers: the list of all LogMatchingTrackers. This is needed because the log processing
+ // is done recursively.
+ // matcherResults: The cached results for all matchers for this event. Parent matchers can
+ // directly access the children's matching results if they have been evaluated.
+ // Otherwise, call children matchers' onLogEvent.
+ virtual void onLogEvent(const LogEventWrapper& event,
+ const std::vector<sp<LogMatchingTracker>>& allTrackers,
+ std::vector<MatchingState>& matcherResults) = 0;
+
+ // Get the tagIds that this matcher cares about. The combined collection is stored
+ // in MetricMananger, so that we can pass any LogEvents that are not interest of us. It uses
+ // some memory but hopefully it can save us much CPU time when there is flood of events.
+ virtual const std::set<int>& getTagIds() const {
+ return mTagIds;
+ }
+
+protected:
+ // Name of this matching. We don't really need the name, but it makes log message easy to debug.
+ const std::string mName;
+
+ // Index of this LogMatchingTracker in MetricsManager's container.
+ const int mIndex;
+
+ // Whether this LogMatchingTracker has been properly initialized.
+ bool mInitialized;
+
+ // The collection of the event tag ids that this LogMatchingTracker cares. So we can quickly
+ // return kNotMatched when we receive an event with an id not in the list. This is especially
+ // useful when we have a complex CombinationLogMatcherTracker.
+ // TODO: Consider use an array instead of stl set. In reality, the number of the tag ids a
+ // LogMatchingTracker cares is only a few.
+ std::set<int> mTagIds;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // LOG_MATCHING_TRACKER_H
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
new file mode 100644
index 000000000000..1c83039072da
--- /dev/null
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SimpleLogMatchingTracker"
+#define DEBUG true // STOPSHIP if true
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
+
+#include "SimpleLogMatchingTracker.h"
+#include <cutils/log.h>
+#include <log/logprint.h>
+
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+SimpleLogMatchingTracker::SimpleLogMatchingTracker(const string& name, const int index,
+ const SimpleLogEntryMatcher& matcher)
+ : LogMatchingTracker(name, index), mMatcher(matcher) {
+ for (int i = 0; i < matcher.tag_size(); i++) {
+ mTagIds.insert(matcher.tag(i));
+ }
+ mInitialized = true;
+}
+
+SimpleLogMatchingTracker::~SimpleLogMatchingTracker() {
+}
+
+bool SimpleLogMatchingTracker::init(const vector<LogEntryMatcher>& allLogMatchers,
+ const vector<sp<LogMatchingTracker>>& allTrackers,
+ const unordered_map<string, int>& matcherMap,
+ vector<bool>& stack) {
+ // no need to do anything.
+ return true;
+}
+
+void SimpleLogMatchingTracker::onLogEvent(const LogEventWrapper& event,
+ const vector<sp<LogMatchingTracker>>& allTrackers,
+ vector<MatchingState>& matcherResults) {
+ if (matcherResults[mIndex] != MatchingState::kNotComputed) {
+ VLOG("Matcher %s already evaluated ", mName.c_str());
+ return;
+ }
+
+ if (mTagIds.find(event.tagId) == mTagIds.end()) {
+ matcherResults[mIndex] = MatchingState::kNotMatched;
+ return;
+ }
+
+ bool matched = matchesSimple(mMatcher, event);
+ matcherResults[mIndex] = matched ? MatchingState::kMatched : MatchingState::kNotMatched;
+ VLOG("Stats SimpleLogMatcher %s matched? %d", mName.c_str(), matched);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
new file mode 100644
index 000000000000..65dbe6476565
--- /dev/null
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef SIMPLE_LOG_MATCHING_TRACKER_H
+#define SIMPLE_LOG_MATCHING_TRACKER_H
+
+#include <log/log_read.h>
+#include <log/logprint.h>
+#include <set>
+#include <unordered_map>
+#include <vector>
+#include "LogMatchingTracker.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class SimpleLogMatchingTracker : public virtual LogMatchingTracker {
+public:
+ SimpleLogMatchingTracker(const std::string& name, const int index,
+ const SimpleLogEntryMatcher& matcher);
+
+ ~SimpleLogMatchingTracker();
+
+ bool init(const std::vector<LogEntryMatcher>& allLogMatchers,
+ const std::vector<sp<LogMatchingTracker>>& allTrackers,
+ const std::unordered_map<std::string, int>& matcherMap,
+ std::vector<bool>& stack) override;
+
+ void onLogEvent(const LogEventWrapper& event,
+ const std::vector<sp<LogMatchingTracker>>& allTrackers,
+ std::vector<MatchingState>& matcherResults) override;
+
+private:
+ const SimpleLogEntryMatcher mMatcher;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#endif // SIMPLE_LOG_MATCHING_TRACKER_H
diff --git a/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index ab7b2b1dc57b..557c03228436 100644
--- a/cmds/statsd/src/matchers/LogEntryMatcherManager.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -14,26 +14,28 @@
* limitations under the License.
*/
-#include "LogEntryMatcherManager.h"
+#include "matcher_util.h"
#include <cutils/log.h>
#include <log/event_tag_map.h>
#include <log/log_event_list.h>
#include <log/logprint.h>
#include <utils/Errors.h>
#include <unordered_map>
+#include "LogMatchingTracker.h"
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "parse_util.h"
+#include "stats_util.h"
using std::set;
using std::string;
using std::unordered_map;
+using std::vector;
namespace android {
namespace os {
namespace statsd {
-LogEventWrapper LogEntryMatcherManager::parseLogEvent(log_msg msg) {
+LogEventWrapper parseLogEvent(log_msg msg) {
LogEventWrapper wrapper;
wrapper.timestamp_ns = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
wrapper.tagId = getTagId(msg);
@@ -67,7 +69,9 @@ LogEventWrapper LogEntryMatcherManager::parseLogEvent(log_msg msg) {
break;
case EVENT_TYPE_STRING:
if (index % 2 == 1) {
- wrapper.strMap[key] = elem.data.string;
+ // without explicit calling string() constructor, there will be an
+ // additional 0 in the end of the string.
+ wrapper.strMap[key] = string(elem.data.string);
}
index++;
break;
@@ -99,57 +103,56 @@ LogEventWrapper LogEntryMatcherManager::parseLogEvent(log_msg msg) {
return wrapper;
}
-bool LogEntryMatcherManager::matches(const LogEntryMatcher& matcher, const LogEventWrapper& event) {
- const int tagId = event.tagId;
- const unordered_map<int, long>& intMap = event.intMap;
- const unordered_map<int, string>& strMap = event.strMap;
- const unordered_map<int, float>& floatMap = event.floatMap;
- const unordered_map<int, bool>& boolMap = event.boolMap;
-
- if (matcher.has_combination()) { // Need to evaluate composite matching
- switch (matcher.combination().operation()) {
- case LogicalOperation::AND:
- for (auto nestedMatcher : matcher.combination().matcher()) {
- if (!matches(nestedMatcher, event)) {
- return false; // return false if any nested matcher is false;
- }
+bool combinationMatch(const vector<int>& children, const LogicalOperation& operation,
+ const vector<MatchingState>& matcherResults) {
+ bool matched;
+ switch (operation) {
+ case LogicalOperation::AND: {
+ matched = true;
+ for (const int childIndex : children) {
+ if (matcherResults[childIndex] != MatchingState::kMatched) {
+ matched = false;
+ break;
}
- return true; // Otherwise, return true.
- case LogicalOperation::OR:
- for (auto nestedMatcher : matcher.combination().matcher()) {
- if (matches(nestedMatcher, event)) {
- return true; // return true if any nested matcher is true;
- }
+ }
+ break;
+ }
+ case LogicalOperation::OR: {
+ matched = false;
+ for (const int childIndex : children) {
+ if (matcherResults[childIndex] == MatchingState::kMatched) {
+ matched = true;
+ break;
}
- return false;
- case LogicalOperation::NOT:
- return !matches(matcher.combination().matcher(0), event);
-
- // Case NAND is just inverting the return statement of AND
- case LogicalOperation::NAND:
- for (auto nestedMatcher : matcher.combination().matcher()) {
- auto simple = nestedMatcher.simple_log_entry_matcher();
- if (!matches(nestedMatcher, event)) {
- return true; // return false if any nested matcher is false;
- }
+ }
+ break;
+ }
+ case LogicalOperation::NOT:
+ matched = matcherResults[children[0]] == MatchingState::kNotMatched;
+ break;
+ case LogicalOperation::NAND:
+ matched = false;
+ for (const int childIndex : children) {
+ if (matcherResults[childIndex] != MatchingState::kMatched) {
+ matched = true;
+ break;
}
- return false; // Otherwise, return true.
- case LogicalOperation::NOR:
- for (auto nestedMatcher : matcher.combination().matcher()) {
- if (matches(nestedMatcher, event)) {
- return false; // return true if any nested matcher is true;
- }
+ }
+ break;
+ case LogicalOperation::NOR:
+ matched = true;
+ for (const int childIndex : children) {
+ if (matcherResults[childIndex] == MatchingState::kMatched) {
+ matched = false;
+ break;
}
- return true;
- }
- return false;
- } else {
- return matchesSimple(matcher.simple_log_entry_matcher(), event);
+ }
+ break;
}
+ return matched;
}
-bool LogEntryMatcherManager::matchesSimple(const SimpleLogEntryMatcher& simpleMatcher,
- const LogEventWrapper& event) {
+bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEventWrapper& event) {
const int tagId = event.tagId;
const unordered_map<int, long>& intMap = event.intMap;
const unordered_map<int, string>& strMap = event.strMap;
@@ -249,26 +252,6 @@ bool LogEntryMatcherManager::matchesSimple(const SimpleLogEntryMatcher& simpleMa
return false;
}
-set<int> LogEntryMatcherManager::getTagIdsFromMatcher(const LogEntryMatcher& matcher) {
- set<int> result;
- switch (matcher.contents_case()) {
- case LogEntryMatcher::kCombination:
- for (auto sub_matcher : matcher.combination().matcher()) {
- set<int> tagSet = getTagIdsFromMatcher(sub_matcher);
- result.insert(tagSet.begin(), tagSet.end());
- }
- break;
- case LogEntryMatcher::kSimpleLogEntryMatcher:
- for (int i = 0; i < matcher.simple_log_entry_matcher().tag_size(); i++) {
- result.insert(matcher.simple_log_entry_matcher().tag(i));
- }
- break;
- case LogEntryMatcher::CONTENTS_NOT_SET:
- break;
- }
- return result;
-}
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/matchers/LogEntryMatcherManager.h b/cmds/statsd/src/matchers/matcher_util.h
index fc8e6a1378a7..6d8e762382f0 100644
--- a/cmds/statsd/src/matchers/LogEntryMatcherManager.h
+++ b/cmds/statsd/src/matchers/matcher_util.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef LOG_ENTRY_MATCHER_MANAGER_H
-#define LOG_ENTRY_MATCHER_MANAGER_H
+#ifndef MATCHER_UTIL_H
+#define MATCHER_UTIL_H
#include <log/log_read.h>
#include <log/logprint.h>
@@ -25,9 +25,6 @@
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-using std::string;
-using std::unordered_map;
-
namespace android {
namespace os {
namespace statsd {
@@ -41,26 +38,20 @@ typedef struct {
std::unordered_map<int, float> floatMap;
} LogEventWrapper;
-/**
- * Keeps track per log entry which simple log entry matchers match.
- */
-class LogEntryMatcherManager {
-public:
- LogEntryMatcherManager();
-
- ~LogEntryMatcherManager(){};
-
- static LogEventWrapper parseLogEvent(log_msg msg);
+enum MatchingState {
+ kNotComputed = -1,
+ kNotMatched = 0,
+ kMatched = 1,
+};
- static std::set<int> getTagIdsFromMatcher(const LogEntryMatcher& matcher);
+LogEventWrapper parseLogEvent(log_msg msg);
- static bool matches(const LogEntryMatcher& matcher, const LogEventWrapper& wrapper);
+bool combinationMatch(const std::vector<int>& children, const LogicalOperation& operation,
+ const std::vector<MatchingState>& matcherResults);
- static bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher,
- const LogEventWrapper& wrapper);
-};
+bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEventWrapper& wrapper);
} // namespace statsd
} // namespace os
} // namespace android
-#endif // LOG_ENTRY_MATCHER_MANAGER_H
+#endif // MATCHER_UTIL_H
diff --git a/cmds/statsd/src/metrics/ConditionTracker.cpp b/cmds/statsd/src/metrics/ConditionTracker.cpp
deleted file mode 100644
index 684ffdb5883a..000000000000
--- a/cmds/statsd/src/metrics/ConditionTracker.cpp
+++ /dev/null
@@ -1,54 +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.
- */
-
-#define LOG_TAG "ConditionTracker"
-#define DEBUG true // STOPSHIP if true
-#define VLOG(...) \
- if (DEBUG) ALOGD(__VA_ARGS__);
-
-#include "ConditionTracker.h"
-#include <cutils/log.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-ConditionTracker::ConditionTracker() : mIsConditionMet(true) {
- VLOG("ConditionTracker()");
-}
-
-ConditionTracker::ConditionTracker(const Condition& condition)
- : mCondition(condition), mIsConditionMet(true) {
- VLOG("ConditionTracker()");
-}
-
-ConditionTracker::~ConditionTracker() {
- VLOG("~ConditionTracker()");
-}
-
-void ConditionTracker::evaluateCondition(const LogEventWrapper& event) {
- // modify condition.
- VLOG("evaluateCondition");
-}
-
-bool ConditionTracker::isConditionMet() const {
- VLOG("isConditionMet() %d", mIsConditionMet);
- return mIsConditionMet;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android \ No newline at end of file
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 635777fe2267..e98999e73223 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -21,7 +21,6 @@
#include "CountMetricProducer.h"
#include "CountAnomalyTracker.h"
-#include "parse_util.h"
#include <cutils/log.h>
#include <limits.h>
@@ -33,15 +32,14 @@ namespace android {
namespace os {
namespace statsd {
-CountMetricProducer::CountMetricProducer(const CountMetric& metric,
- const sp<ConditionTracker> condition)
+CountMetricProducer::CountMetricProducer(const CountMetric& metric, const bool hasCondition)
: mMetric(metric),
- mConditionTracker(condition),
- mStartTime(std::time(nullptr)),
+ mStartTime(time(nullptr)),
mCounter(0),
mCurrentBucketStartTime(mStartTime),
// TODO: read mAnomalyTracker parameters from config file.
- mAnomalyTracker(6, 10) {
+ mAnomalyTracker(6, 10),
+ mCondition(hasCondition ? ConditionState::kUnknown : ConditionState::kTrue) {
// TODO: evaluate initial conditions. and set mConditionMet.
if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
mBucketSize_sec = metric.bucket().bucket_size_millis() / 1000;
@@ -52,10 +50,6 @@ CountMetricProducer::CountMetricProducer(const CountMetric& metric,
VLOG("created. bucket size %lu start_time: %lu", mBucketSize_sec, mStartTime);
}
-CountMetricProducer::CountMetricProducer(const CountMetric& metric)
- : CountMetricProducer(metric, new ConditionTracker()) {
-}
-
CountMetricProducer::~CountMetricProducer() {
VLOG("~CountMetricProducer() called");
}
@@ -63,13 +57,17 @@ CountMetricProducer::~CountMetricProducer() {
void CountMetricProducer::finish() {
// TODO: write the StatsLogReport to dropbox using
// DropboxWriter.
- onDumpReport();
}
void CountMetricProducer::onDumpReport() {
VLOG("dump report now...");
}
+void CountMetricProducer::onConditionChanged(const bool conditionMet) {
+ VLOG("onConditionChanged");
+ mCondition = conditionMet;
+}
+
void CountMetricProducer::onMatchedLogEvent(const LogEventWrapper& event) {
time_t eventTime = event.timestamp_ns / 1000000000;
@@ -78,22 +76,24 @@ void CountMetricProducer::onMatchedLogEvent(const LogEventWrapper& event) {
return;
}
- if (mConditionTracker->isConditionMet()) {
+ if (mCondition == ConditionState::kTrue) {
flushCounterIfNeeded(eventTime);
mCounter++;
mAnomalyTracker.checkAnomaly(mCounter);
+ VLOG("metric %lld count %d", mMetric.metric_id(), mCounter);
}
}
-// When a new matched event comes in, we check if it falls into the current bucket. And flush the
-// counter to the StatsLogReport and adjust the bucket if needed.
+// When a new matched event comes in, we check if it falls into the current
+// bucket. And flush the counter to the StatsLogReport and adjust the bucket if
+// needed.
void CountMetricProducer::flushCounterIfNeeded(const time_t& eventTime) {
if (mCurrentBucketStartTime + mBucketSize_sec > eventTime) {
return;
}
// TODO: add a KeyValuePair to StatsLogReport.
- ALOGD("CountMetric: dump counter %d", mCounter);
+ ALOGD("%lld: dump counter %d", mMetric.metric_id(), mCounter);
// adjust the bucket start time
time_t numBucketsForward = (eventTime - mCurrentBucketStartTime)
@@ -106,7 +106,7 @@ void CountMetricProducer::flushCounterIfNeeded(const time_t& eventTime) {
mAnomalyTracker.addPastBucket(mCounter, numBucketsForward);
mCounter = 0;
- VLOG("new bucket start time: %lu", mCurrentBucketStartTime);
+ VLOG("%lld: new bucket start time: %lu", mMetric.metric_id(), mCurrentBucketStartTime);
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 7502320410ac..370cd4684458 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -17,40 +17,41 @@
#ifndef COUNT_METRIC_PRODUCER_H
#define COUNT_METRIC_PRODUCER_H
-#include <mutex>
-#include <thread>
#include <unordered_map>
-#include "../matchers/LogEntryMatcherManager.h"
+
#include "CountAnomalyTracker.h"
-#include "ConditionTracker.h"
-#include "DropboxWriter.h"
+#include "../condition/ConditionTracker.h"
+#include "../matchers/matcher_util.h"
#include "MetricProducer.h"
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+using namespace std;
+
namespace android {
namespace os {
namespace statsd {
class CountMetricProducer : public MetricProducer {
public:
- CountMetricProducer(const CountMetric& countMetric, const sp<ConditionTracker> condition);
-
- CountMetricProducer(const CountMetric& countMetric);
+ CountMetricProducer(const CountMetric& countMetric, const bool hasCondition);
virtual ~CountMetricProducer();
void onMatchedLogEvent(const LogEventWrapper& event) override;
+ void onConditionChanged(const bool conditionMet) override;
+
void finish() override;
void onDumpReport() override;
+ // TODO: Implement this later.
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override {};
+
private:
const CountMetric mMetric;
- const sp<ConditionTracker> mConditionTracker;
-
const time_t mStartTime;
// TODO: Add dimensions.
// Counter value for the current bucket.
@@ -62,6 +63,8 @@ private:
CountAnomalyTracker mAnomalyTracker;
+ bool mCondition;
+
void flushCounterIfNeeded(const time_t& newEventTime);
};
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 44a778b3d903..b7e965610020 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -18,21 +18,27 @@
#define METRIC_PRODUCER_H
#include <log/logprint.h>
-#include "../matchers/LogEntryMatcherManager.h"
+#include <utils/RefBase.h>
+#include "../matchers/matcher_util.h"
+#include "PackageInfoListener.h"
namespace android {
namespace os {
namespace statsd {
// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
-// writing the report to dropbox.
-class MetricProducer {
+// 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
+// be a no-op.
+class MetricProducer : public virtual RefBase, public virtual PackageInfoListener {
public:
virtual ~MetricProducer(){};
- // Consume the stats log if it's interesting to this metric.
+ // Consume the parsed stats log entry that already matched the "what" of the metric.
virtual void onMatchedLogEvent(const LogEventWrapper& event) = 0;
+ virtual void onConditionChanged(const bool condition) = 0;
+
// This is called when the metric collecting is done, e.g., when there is a new configuration
// coming. MetricProducer should do the clean up, and dump existing data to dropbox.
virtual void finish() = 0;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index cb7420683380..1e65f5888233 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -21,13 +21,17 @@
#include "MetricsManager.h"
#include <cutils/log.h>
#include <log/logprint.h>
+#include "../condition/CombinationConditionTracker.h"
+#include "../condition/SimpleConditionTracker.h"
+#include "../matchers/CombinationLogMatchingTracker.h"
+#include "../matchers/SimpleLogMatchingTracker.h"
#include "CountMetricProducer.h"
-#include "parse_util.h"
+#include "metrics_manager_util.h"
+#include "stats_util.h"
using std::make_unique;
using std::set;
using std::string;
-using std::unique_ptr;
using std::unordered_map;
using std::vector;
@@ -35,93 +39,90 @@ namespace android {
namespace os {
namespace statsd {
-MetricsManager::MetricsManager(const StatsdConfig& config) : mConfig(config), mLogMatchers() {
- std::unordered_map<string, LogEntryMatcher> matcherMap;
- std::unordered_map<string, sp<ConditionTracker>> conditionMap;
-
- for (int i = 0; i < config.log_entry_matcher_size(); i++) {
- const LogEntryMatcher& logMatcher = config.log_entry_matcher(i);
- mMatchers.push_back(logMatcher);
-
- matcherMap[config.log_entry_matcher(i).name()] = logMatcher;
-
- mLogMatchers[logMatcher.name()] = vector<unique_ptr<MetricProducer>>();
- // Collect all the tag ids that are interesting
- set<int> tagIds = LogEntryMatcherManager::getTagIdsFromMatcher(logMatcher);
-
- mTagIds.insert(tagIds.begin(), tagIds.end());
- }
-
- for (int i = 0; i < config.condition_size(); i++) {
- const Condition& condition = config.condition(i);
- conditionMap[condition.name()] = new ConditionTracker(condition);
- }
-
- // Build MetricProducers for each metric defined in config.
- // (1) build CountMetricProducer
- for (int i = 0; i < config.count_metric_size(); i++) {
- const CountMetric& metric = config.count_metric(i);
- auto it = mLogMatchers.find(metric.what());
- if (it == mLogMatchers.end()) {
- ALOGW("cannot find the LogEntryMatcher %s in config", metric.what().c_str());
- continue;
- }
-
- if (metric.has_condition()) {
- auto condition_it = conditionMap.find(metric.condition());
- if (condition_it == conditionMap.end()) {
- ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
- continue;
- }
- it->second.push_back(make_unique<CountMetricProducer>(metric, condition_it->second));
- } else {
- it->second.push_back(make_unique<CountMetricProducer>(metric));
- }
- }
-
- // TODO: build other types of metrics too.
+MetricsManager::MetricsManager(const StatsdConfig& config) {
+ mConfigValid = initStatsdConfig(config, mTagIds, mAllLogEntryMatchers, mAllConditionTrackers,
+ mAllMetricProducers, mConditionToMetricMap, mTrackerToMetricMap,
+ mTrackerToConditionMap);
}
MetricsManager::~MetricsManager() {
VLOG("~MetricManager()");
}
+bool MetricsManager::isConfigValid() const {
+ return mConfigValid;
+}
+
void MetricsManager::finish() {
- for (auto const& entryPair : mLogMatchers) {
- for (auto const& metric : entryPair.second) {
- metric->finish();
- }
+ for (auto& metricProducer : mAllMetricProducers) {
+ metricProducer->finish();
}
}
// Consume the stats log if it's interesting to this metric.
void MetricsManager::onLogEvent(const log_msg& logMsg) {
+ if (!mConfigValid) {
+ return;
+ }
+
int tagId = getTagId(logMsg);
if (mTagIds.find(tagId) == mTagIds.end()) {
// not interesting...
return;
}
+
// Since at least one of the metrics is interested in this event, we parse it now.
- LogEventWrapper event = LogEntryMatcherManager::parseLogEvent(logMsg);
+ LogEventWrapper event = parseLogEvent(logMsg);
+ vector<MatchingState> matcherCache(mAllLogEntryMatchers.size(), MatchingState::kNotComputed);
- // Evaluate the conditions. Order matters, this should happen
- // before sending the event to metrics
- for (auto& condition : mConditionTracker) {
- condition->evaluateCondition(event);
+ for (auto& matcher : mAllLogEntryMatchers) {
+ matcher->onLogEvent(event, mAllLogEntryMatchers, matcherCache);
+ }
+
+ // A bitmap to see which ConditionTracker needs to be re-evaluated.
+ vector<bool> conditionToBeEvaluated(mAllConditionTrackers.size(), false);
+
+ for (const auto& pair : mTrackerToConditionMap) {
+ if (matcherCache[pair.first] == MatchingState::kMatched) {
+ const auto& conditionList = pair.second;
+ for (const int conditionIndex : conditionList) {
+ conditionToBeEvaluated[conditionIndex] = true;
+ }
+ }
+ }
+
+ vector<ConditionState> conditionCache(mAllConditionTrackers.size(),
+ ConditionState::kNotEvaluated);
+ // A bitmap to track if a condition has changed value.
+ vector<bool> changedCache(mAllConditionTrackers.size(), false);
+ for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
+ if (conditionToBeEvaluated[i] == false) {
+ continue;
+ }
+
+ sp<ConditionTracker>& condition = mAllConditionTrackers[i];
+ condition->evaluateCondition(event, matcherCache, mAllConditionTrackers, conditionCache,
+ changedCache);
+ if (changedCache[i]) {
+ auto pair = mConditionToMetricMap.find(i);
+ if (pair != mConditionToMetricMap.end()) {
+ auto& metricList = pair->second;
+ for (auto metricIndex : metricList) {
+ mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i]);
+ }
+ }
+ }
}
- // Now find out which LogMatcher matches this event, and let relevant metrics know.
- for (auto matcher : mMatchers) {
- if (LogEntryMatcherManager::matches(matcher, event)) {
- auto it = mLogMatchers.find(matcher.name());
- if (it != mLogMatchers.end()) {
- for (auto const& it2 : it->second) {
- // Only metrics that matches this event get notified.
- it2->onMatchedLogEvent(event);
+ // For matched LogEntryMatchers, tell relevant metrics that a matched event has come.
+ for (size_t i = 0; i < mAllLogEntryMatchers.size(); i++) {
+ if (matcherCache[i] == MatchingState::kMatched) {
+ auto pair = mTrackerToMetricMap.find(i);
+ if (pair != mTrackerToMetricMap.end()) {
+ auto& metricList = pair->second;
+ for (const int metricIndex : metricList) {
+ mAllMetricProducers[metricIndex]->onMatchedLogEvent(event);
}
- } else {
- // TODO: we should remove any redundant matchers that the config provides.
- ALOGW("Matcher not used by any metrics.");
}
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 77d7535a1ba1..70c34db6b80a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -20,8 +20,8 @@
#include <cutils/log.h>
#include <log/logprint.h>
#include <unordered_map>
-#include "../matchers/LogEntryMatcherManager.h"
-#include "ConditionTracker.h"
+#include "../condition/ConditionTracker.h"
+#include "../matchers/LogMatchingTracker.h"
#include "MetricProducer.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -36,25 +36,58 @@ public:
~MetricsManager();
- // Consume the stats log if it's interesting to this metric.
+ // Return whether the configuration is valid.
+ bool isConfigValid() const;
+
void onLogEvent(const log_msg& logMsg);
+ // Called when everything should wrap up. We are about to finish (e.g., new config comes).
void finish();
private:
- const StatsdConfig mConfig;
-
// All event tags that are interesting to my metrics.
std::set<int> mTagIds;
- // The matchers that my metrics share.
- std::vector<LogEntryMatcher> mMatchers;
+ // We only store the sp of LogMatchingTracker, MetricProducer, and ConditionTracker in
+ // MetricManager. There are relationship between them, and the relationship are denoted by index
+ // instead of poiters. The reasons for this are: (1) the relationship between them are
+ // complicated, store index instead of pointers reduce the risk of A holds B's sp, and B holds
+ // A's sp. (2) When we evaluate matcher results, or condition results, we can quickly get the
+ // related results from a cache using the index.
+ // TODO: using unique_ptr may be more appriopreate?
+
+ // Hold all the log entry matchers from the config.
+ std::vector<sp<LogMatchingTracker>> mAllLogEntryMatchers;
+
+ // Hold all the conditions from the config.
+ std::vector<sp<ConditionTracker>> mAllConditionTrackers;
+
+ // Hold all metrics from the config.
+ std::vector<sp<MetricProducer>> mAllMetricProducers;
+
+ // To make the log processing more efficient, we want to do as much filtering as possible
+ // before we go into individual trackers and conditions to match.
+
+ // 1st filter: check if the event tag id is in mTagIds.
+ // 2nd filter: if it is, we parse the event because there is at least one member is interested.
+ // then pass to all LogMatchingTrackers (itself also filter events by ids).
+ // 3nd filter: for LogMatchingTrackers that matched this event, we pass this event to the
+ // ConditionTrackers and MetricProducers that use this matcher.
+ // 4th filter: for ConditionTrackers that changed value due to this event, we pass
+ // new conditions to metrics that use this condition.
+
+ // The following map is initialized from the statsd_config.
+
+ // maps from the index of the LogMatchingTracker to index of MetricProducer.
+ std::unordered_map<int, std::vector<int>> mTrackerToMetricMap;
+
+ // maps from LogMatchingTracker to ConditionTracker
+ std::unordered_map<int, std::vector<int>> mTrackerToConditionMap;
- // The conditions that my metrics share.
- std::vector<sp<ConditionTracker>> mConditionTracker;
+ // maps from ConditionTracker to MetricProducer
+ std::unordered_map<int, std::vector<int>> mConditionToMetricMap;
- // the map from LogEntryMatcher names to the metrics that use this matcher.
- std::unordered_map<std::string, std::vector<std::unique_ptr<MetricProducer>>> mLogMatchers;
+ bool mConfigValid;
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
new file mode 100644
index 000000000000..6fdd228f4910
--- /dev/null
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -0,0 +1,200 @@
+/*
+ * 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 "../condition/CombinationConditionTracker.h"
+#include "../condition/SimpleConditionTracker.h"
+#include "../matchers/CombinationLogMatchingTracker.h"
+#include "../matchers/SimpleLogMatchingTracker.h"
+#include "CountMetricProducer.h"
+#include "stats_util.h"
+
+using std::set;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+bool initLogTrackers(const StatsdConfig& config, unordered_map<string, int>& logTrackerMap,
+ vector<sp<LogMatchingTracker>>& allLogEntryMatchers, set<int>& allTagIds) {
+ vector<LogEntryMatcher> matcherConfigs;
+
+ for (int i = 0; i < config.log_entry_matcher_size(); i++) {
+ const LogEntryMatcher& logMatcher = config.log_entry_matcher(i);
+
+ int index = allLogEntryMatchers.size();
+ switch (logMatcher.contents_case()) {
+ case LogEntryMatcher::ContentsCase::kSimpleLogEntryMatcher:
+ allLogEntryMatchers.push_back(new SimpleLogMatchingTracker(
+ logMatcher.name(), index, logMatcher.simple_log_entry_matcher()));
+ break;
+ case LogEntryMatcher::ContentsCase::kCombination:
+ allLogEntryMatchers.push_back(
+ new CombinationLogMatchingTracker(logMatcher.name(), index));
+ break;
+ default:
+ ALOGE("Matcher %s malformed", logMatcher.name().c_str());
+ return false;
+ // continue;
+ }
+ if (logTrackerMap.find(logMatcher.name()) != logTrackerMap.end()) {
+ ALOGE("Duplicate LogEntryMatcher found!");
+ return false;
+ }
+ logTrackerMap[logMatcher.name()] = index;
+ matcherConfigs.push_back(logMatcher);
+ }
+
+ vector<bool> stackTracker2(allLogEntryMatchers.size(), false);
+ for (auto& matcher : allLogEntryMatchers) {
+ if (!matcher->init(matcherConfigs, allLogEntryMatchers, logTrackerMap, stackTracker2)) {
+ return false;
+ }
+ // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only.
+ const set<int>& tagIds = matcher->getTagIds();
+ allTagIds.insert(tagIds.begin(), tagIds.end());
+ }
+ return true;
+}
+
+bool initConditions(const StatsdConfig& config, const unordered_map<string, int>& logTrackerMap,
+ unordered_map<string, int>& conditionTrackerMap,
+ vector<sp<ConditionTracker>>& allConditionTrackers,
+ unordered_map<int, std::vector<int>>& trackerToConditionMap) {
+ vector<Condition> conditionConfigs;
+
+ for (int i = 0; i < config.condition_size(); i++) {
+ const Condition& condition = config.condition(i);
+ int index = allConditionTrackers.size();
+ switch (condition.contents_case()) {
+ case Condition::ContentsCase::kSimpleCondition: {
+ allConditionTrackers.push_back(new SimpleConditionTracker(
+ condition.name(), index, condition.simple_condition(), logTrackerMap));
+ break;
+ }
+ case Condition::ContentsCase::kCombination: {
+ allConditionTrackers.push_back(
+ new CombinationConditionTracker(condition.name(), index));
+ break;
+ }
+ default:
+ ALOGE("Condition %s malformed", condition.name().c_str());
+ return false;
+ }
+ if (conditionTrackerMap.find(condition.name()) != conditionTrackerMap.end()) {
+ ALOGE("Duplicate Condition found!");
+ return false;
+ }
+ conditionTrackerMap[condition.name()] = index;
+ conditionConfigs.push_back(condition);
+ }
+
+ vector<bool> stackTracker(allConditionTrackers.size(), false);
+ for (size_t i = 0; i < allConditionTrackers.size(); i++) {
+ auto& conditionTracker = allConditionTrackers[i];
+ if (!conditionTracker->init(conditionConfigs, allConditionTrackers, conditionTrackerMap,
+ stackTracker)) {
+ return false;
+ }
+ for (const int trackerIndex : conditionTracker->getLogTrackerIndex()) {
+ auto& conditionList = trackerToConditionMap[trackerIndex];
+ conditionList.push_back(i);
+ }
+ }
+ return true;
+}
+
+bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& logTrackerMap,
+ const unordered_map<string, int>& conditionTrackerMap,
+ vector<sp<MetricProducer>>& allMetricProducers,
+ unordered_map<int, std::vector<int>>& conditionToMetricMap,
+ unordered_map<int, std::vector<int>>& trackerToMetricMap) {
+ // Build MetricProducers for each metric defined in config.
+ // (1) build CountMetricProducer
+ for (int i = 0; i < config.count_metric_size(); i++) {
+ const CountMetric& metric = config.count_metric(i);
+ if (!metric.has_what()) {
+ ALOGW("cannot find what in CountMetric %lld", metric.metric_id());
+ return false;
+ }
+
+ auto logTrackerIt = logTrackerMap.find(metric.what());
+ if (logTrackerIt == logTrackerMap.end()) {
+ ALOGW("cannot find the LogEntryMatcher %s in config", metric.what().c_str());
+ return false;
+ }
+
+ sp<MetricProducer> countProducer;
+ int metricIndex = allMetricProducers.size();
+ if (metric.has_condition()) {
+ auto condition_it = conditionTrackerMap.find(metric.condition());
+ if (condition_it == conditionTrackerMap.end()) {
+ ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
+ return false;
+ }
+ countProducer = new CountMetricProducer(metric, true /*has condition*/);
+ // will create new vector if not exist before.
+ auto& metricList = conditionToMetricMap[condition_it->second];
+ metricList.push_back(metricIndex);
+ } else {
+ countProducer = new CountMetricProducer(metric, false /*no condition*/);
+ }
+
+ int logTrackerIndex = logTrackerIt->second;
+ auto& metric_list = trackerToMetricMap[logTrackerIndex];
+ metric_list.push_back(metricIndex);
+ allMetricProducers.push_back(countProducer);
+ }
+
+ // TODO: build other types of metrics too.
+
+ return true;
+}
+
+bool initStatsdConfig(const StatsdConfig& config, set<int>& allTagIds,
+ vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+ vector<sp<ConditionTracker>>& allConditionTrackers,
+ vector<sp<MetricProducer>>& allMetricProducers,
+ unordered_map<int, std::vector<int>>& conditionToMetricMap,
+ unordered_map<int, std::vector<int>>& trackerToMetricMap,
+ unordered_map<int, std::vector<int>>& trackerToConditionMap) {
+ unordered_map<string, int> logTrackerMap;
+ unordered_map<string, int> conditionTrackerMap;
+
+ if (!initLogTrackers(config, logTrackerMap, allLogEntryMatchers, allTagIds)) {
+ ALOGE("initLogMatchingTrackers failed");
+ return false;
+ }
+
+ if (!initConditions(config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
+ trackerToConditionMap)) {
+ ALOGE("initConditionTrackers failed");
+ return false;
+ }
+
+ if (!initMetrics(config, logTrackerMap, conditionTrackerMap, allMetricProducers,
+ conditionToMetricMap, trackerToMetricMap)) {
+ ALOGE("initMetricProducers failed");
+ return false;
+ }
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
new file mode 100644
index 000000000000..5f1f295d450a
--- /dev/null
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+#ifndef METRIC_UTIL_H
+#define METRIC_UTIL_H
+#include <memory>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+#include "../condition/ConditionTracker.h"
+#include "../matchers/LogMatchingTracker.h"
+#include "CountMetricProducer.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Helper functions for MetricsManager to initialize from StatsdConfig.
+// *Note*: only initStatsdConfig() should be called from outside.
+// All other functions are intermediate
+// steps, created to make unit tests easier. And most of the parameters in these
+// functions are temporary objects in the initialization phase.
+
+// Initialize the LogMatchingTrackers.
+// input:
+// [config]: the input StatsdConfig
+// output:
+// [logTrackerMap]: this map should contain matcher name to index mapping
+// [allLogEntryMatchers]: should store the sp to all the LogMatchingTracker
+// [allTagIds]: contains the set of all interesting tag ids to this config.
+bool initLogTrackers(const StatsdConfig& config,
+ std::unordered_map<std::string, int>& logTrackerMap,
+ std::vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+ std::set<int>& allTagIds);
+
+// Initialize ConditionTrackers
+// input:
+// [config]: the input config
+// [logTrackerMap]: LogMatchingTracker name to index mapping from previous step.
+// output:
+// [conditionTrackerMap]: this map should contain condition name to index mapping
+// [allConditionTrackers]: stores the sp to all the ConditionTrackers
+// [trackerToConditionMap]: contain the mapping from index of
+// log tracker to condition trackers that use the log tracker
+bool initConditions(const StatsdConfig& config,
+ const std::unordered_map<std::string, int>& logTrackerMap,
+ std::unordered_map<std::string, int>& conditionTrackerMap,
+ std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
+
+// Initialize MetricProducers.
+// input:
+// [config]: the input config
+// [logTrackerMap]: LogMatchingTracker name to index mapping from previous step.
+// [conditionTrackerMap]: condition name to index mapping
+// output:
+// [allMetricProducers]: contains the list of sp to the MetricProducers created.
+// [conditionToMetricMap]: contains the mapping from condition tracker index to
+// the list of MetricProducer index
+// [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
+bool initMetrics(const StatsdConfig& config,
+ const std::unordered_map<std::string, int>& logTrackerMap,
+ const std::unordered_map<std::string, int>& conditionTrackerMap,
+ std::vector<sp<MetricProducer>>& allMetricProducers,
+ std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
+ std::unordered_map<int, std::vector<int>>& trackerToMetricMap);
+
+// Initialize MetricManager from StatsdConfig.
+// Parameters are the members of MetricsManager. See MetricsManager for declaration.
+bool initStatsdConfig(const StatsdConfig& config, std::set<int>& allTagIds,
+ std::vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
+ std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ std::vector<sp<MetricProducer>>& allMetricProducers,
+ std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
+ std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
+ std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#endif // METRIC_UTIL_H
diff --git a/cmds/statsd/src/parse_util.cpp b/cmds/statsd/src/parse_util.cpp
deleted file mode 100644
index 61421880efd6..000000000000
--- a/cmds/statsd/src/parse_util.cpp
+++ /dev/null
@@ -1,132 +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 <log/log_event_list.h>
-#include <parse_util.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static inline uint32_t get4LE(const char* src) {
- return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
-}
-
-int getTagId(log_msg msg) {
- return get4LE(msg.msg());
-}
-
-EventMetricData parse(log_msg msg) {
- // dump all statsd logs to dropbox for now.
- // TODO: Add filtering, aggregation, etc.
- EventMetricData eventMetricData;
-
- // set tag.
- int tag = getTagId(msg);
- // TODO: Replace the following line when we can serialize on the fly.
- //eventMetricData.set_tag(tag);
-
- // set timestamp of the event.
- eventMetricData.set_timestamp_nanos(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec);
-
- // start iterating k,v pairs.
- android_log_context context =
- create_android_log_parser(const_cast<log_msg*>(&msg)->msg() + sizeof(uint32_t),
- const_cast<log_msg*>(&msg)->len() - sizeof(uint32_t));
- android_log_list_element elem;
-
- if (context) {
- memset(&elem, 0, sizeof(elem));
- size_t index = 0;
- int32_t key = -1;
-
- do {
- elem = android_log_read_next(context);
- switch ((int)elem.type) {
- case EVENT_TYPE_INT:
- if (index % 2 == 0) {
- key = elem.data.int32;
- } else {
- // TODO: Fix the following lines when we can serialize on the fly.
- /*
- int32_t val = elem.data.int32;
- KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(key);
- keyValuePair->set_value_int(val);
- */
- }
- index++;
- break;
- case EVENT_TYPE_FLOAT:
- if (index % 2 == 1) {
- // TODO: Fix the following lines when we can serialize on the fly.
- /*
- float val = elem.data.float32;
- KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(key);
- keyValuePair->set_value_float(val);
- */
- }
- index++;
- break;
- case EVENT_TYPE_STRING:
- if (index % 2 == 1) {
- // TODO: Fix the following lines when we can serialize on the fly.
- /*
- char* val = elem.data.string;
- KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(key);
- keyValuePair->set_value_str(val);
- */
- }
- index++;
- break;
- case EVENT_TYPE_LONG:
- if (index % 2 == 1) {
- // TODO: Fix the following lines when we can serialize on the fly.
- /*
- int64_t val = elem.data.int64;
- KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
- keyValuePair->set_key(key);
- keyValuePair->set_value_int(val);
- */
- }
- index++;
- break;
- case EVENT_TYPE_LIST:
- break;
- case EVENT_TYPE_LIST_STOP:
- break;
- case EVENT_TYPE_UNKNOWN:
- break;
- default:
- elem.complete = true;
- break;
- }
-
- if (elem.complete) {
- break;
- }
- } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
-
- android_log_destroy(&context);
- }
-
- return eventMetricData;
-}
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 2dc0cc7b4a6b..6421b70f1f86 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -55,6 +55,43 @@ message CountMetricData {
repeated CountBucketInfo bucket_info = 2;
}
+message DurationBucketInfo {
+ optional int64 start_bucket_nanos = 1;
+
+ optional int64 end_bucket_nanos = 2;
+
+ optional int64 duration_nanos = 3;
+}
+
+message DurationMetricData {
+ repeated KeyValuePair dimension = 1;
+
+ repeated DurationBucketInfo bucket_info = 2;
+}
+
+message UidMapping {
+ message AppInfo {
+ optional string app = 1;
+
+ optional int32 version = 2;
+
+ optional int32 uid = 3;
+ }
+
+ repeated AppInfo initial = 1;
+
+ message Change {
+ optional bool deletion = 1;
+
+ optional int64 timestamp = 2;
+ optional string app = 3;
+ optional int32 uid = 4;
+
+ optional int32 version = 5;
+ }
+ repeated Change changes = 2;
+}
+
message StatsLogReport {
optional int32 metric_id = 1;
@@ -68,8 +105,12 @@ message StatsLogReport {
message CountMetricDataWrapper {
repeated CountMetricData data = 1;
}
+ message DurationMetricDataWrapper {
+ repeated CountMetricData data = 1;
+ }
oneof data {
EventMetricDataWrapper event_metrics = 4;
CountMetricDataWrapper count_metrics = 5;
+ DurationMetricDataWrapper duration_metrics = 6;
}
}
diff --git a/cmds/statsd/src/stats_util.cpp b/cmds/statsd/src/stats_util.cpp
new file mode 100644
index 000000000000..978b228891b5
--- /dev/null
+++ b/cmds/statsd/src/stats_util.cpp
@@ -0,0 +1,289 @@
+/*
+ * 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 <log/log_event_list.h>
+#include "stats_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static inline uint32_t get4LE(const char* src) {
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+int getTagId(log_msg msg) {
+ return get4LE(msg.msg());
+}
+
+EventMetricData parse(log_msg msg) {
+ // dump all statsd logs to dropbox for now.
+ // TODO: Add filtering, aggregation, etc.
+ EventMetricData eventMetricData;
+
+ // set tag.
+ int tag = getTagId(msg);
+ // TODO: Replace the following line when we can serialize on the fly.
+ // eventMetricData.set_tag(tag);
+
+ // set timestamp of the event.
+ eventMetricData.set_timestamp_nanos(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec);
+
+ // start iterating k,v pairs.
+ android_log_context context =
+ create_android_log_parser(const_cast<log_msg*>(&msg)->msg() + sizeof(uint32_t),
+ const_cast<log_msg*>(&msg)->len() - sizeof(uint32_t));
+ android_log_list_element elem;
+
+ if (context) {
+ memset(&elem, 0, sizeof(elem));
+ size_t index = 0;
+ int32_t key = -1;
+
+ do {
+ elem = android_log_read_next(context);
+ switch ((int)elem.type) {
+ case EVENT_TYPE_INT:
+ if (index % 2 == 0) {
+ key = elem.data.int32;
+ } else {
+ // TODO: Fix the following lines when we can serialize on the fly.
+ /*
+ int32_t val = elem.data.int32;
+ KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
+ keyValuePair->set_key(key);
+ keyValuePair->set_value_int(val);
+ */
+ }
+ index++;
+ break;
+ case EVENT_TYPE_FLOAT:
+ if (index % 2 == 1) {
+ // TODO: Fix the following lines when we can serialize on the fly.
+ /*
+ float val = elem.data.float32;
+ KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
+ keyValuePair->set_key(key);
+ keyValuePair->set_value_float(val);
+ */
+ }
+ index++;
+ break;
+ case EVENT_TYPE_STRING:
+ if (index % 2 == 1) {
+ // TODO: Fix the following lines when we can serialize on the fly.
+ /*
+ char* val = elem.data.string;
+ KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
+ keyValuePair->set_key(key);
+ keyValuePair->set_value_str(val);
+ */
+ }
+ index++;
+ break;
+ case EVENT_TYPE_LONG:
+ if (index % 2 == 1) {
+ // TODO: Fix the following lines when we can serialize on the fly.
+ /*
+ int64_t val = elem.data.int64;
+ KeyValuePair* keyValuePair = eventMetricData.add_key_value_pair();
+ keyValuePair->set_key(key);
+ keyValuePair->set_value_int(val);
+ */
+ }
+ index++;
+ break;
+ case EVENT_TYPE_LIST:
+ break;
+ case EVENT_TYPE_LIST_STOP:
+ break;
+ case EVENT_TYPE_UNKNOWN:
+ break;
+ default:
+ elem.complete = true;
+ break;
+ }
+
+ if (elem.complete) {
+ break;
+ }
+ } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
+
+ android_log_destroy(&context);
+ }
+
+ return eventMetricData;
+}
+
+StatsdConfig buildFakeConfig() {
+ // HACK: Hard code a test metric for counting screen on events...
+ StatsdConfig config;
+ config.set_config_id(12345L);
+
+ // One count metric to count screen on
+ CountMetric* metric = config.add_count_metric();
+ metric->set_metric_id(20150717L);
+ metric->set_what("SCREEN_IS_ON");
+ metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+
+ // One count metric to count PHOTO_CHANGE_OR_CHROME_CRASH
+ metric = config.add_count_metric();
+ metric->set_metric_id(20150718L);
+ metric->set_what("PHOTO_PROCESS_STATE_CHANGE");
+ metric->mutable_bucket()->set_bucket_size_millis(60 * 1000L);
+ metric->set_condition("SCREEN_IS_ON");
+
+
+ LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_ON");
+
+ SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+
+
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_OFF");
+
+ simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
+
+
+
+ LogEntryMatcher* procEventMatcher = config.add_log_entry_matcher();
+ procEventMatcher->set_name("PHOTO_CRASH");
+
+ SimpleLogEntryMatcher* simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
+ KeyValueMatcher* keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(
+ 1002 /*pkg*/);
+ keyValueMatcher->set_eq_string(
+ "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ keyValueMatcher->set_eq_int(2);
+
+
+ procEventMatcher = config.add_log_entry_matcher();
+ procEventMatcher->set_name("PHOTO_START");
+
+ simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
+ keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(
+ 1002 /*pkg*/);
+ keyValueMatcher->set_eq_string(
+ "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(
+ 1 /*STATE*/);
+ keyValueMatcher->set_eq_int(1);
+
+
+ procEventMatcher = config.add_log_entry_matcher();
+ procEventMatcher->set_name("PHOTO_PROCESS_STATE_CHANGE");
+ LogEntryMatcher_Combination* combinationMatcher = procEventMatcher->mutable_combination();
+ combinationMatcher->set_operation(LogicalOperation::OR);
+ combinationMatcher->add_matcher("PHOTO_START");
+ combinationMatcher->add_matcher("PHOTO_CRASH");
+
+
+ procEventMatcher = config.add_log_entry_matcher();
+ procEventMatcher->set_name("CHROME_CRASH");
+
+ simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
+ keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(
+ 1002 /*pkg*/);
+ keyValueMatcher->set_eq_string(
+ "com.android.chrome" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(
+ 1 /*STATE*/);
+ keyValueMatcher->set_eq_int(2);
+
+
+
+ procEventMatcher = config.add_log_entry_matcher();
+ procEventMatcher->set_name("PHOTO_CHANGE_OR_CHROME_CRASH");
+ combinationMatcher = procEventMatcher->mutable_combination();
+ combinationMatcher->set_operation(LogicalOperation::OR);
+ combinationMatcher->add_matcher("PHOTO_PROCESS_STATE_CHANGE");
+ combinationMatcher->add_matcher("CHROME_CRASH");
+
+
+
+ Condition* condition = config.add_condition();
+ condition->set_name("SCREEN_IS_ON");
+ SimpleCondition* simpleCondition = condition->mutable_simple_condition();
+ simpleCondition->set_start("SCREEN_IS_ON");
+ simpleCondition->set_stop("SCREEN_IS_OFF");
+
+
+ condition = config.add_condition();
+ condition->set_name("PHOTO_STARTED");
+
+ simpleCondition = condition->mutable_simple_condition();
+ simpleCondition->set_start("PHOTO_START");
+ simpleCondition->set_stop("PHOTO_CRASH");
+
+
+ condition = config.add_condition();
+ condition->set_name("SCREEN_IS_OFF");
+
+ simpleCondition = condition->mutable_simple_condition();
+ simpleCondition->set_start("SCREEN_IS_OFF");
+ simpleCondition->set_stop("SCREEN_IS_ON");
+
+
+ condition = config.add_condition();
+ condition->set_name("SCREEN_IS_EITHER_ON_OFF");
+
+ Condition_Combination* combination = condition->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_condition("SCREEN_IS_ON");
+ combination->add_condition("SCREEN_IS_OFF");
+
+
+ condition = config.add_condition();
+ condition->set_name("SCREEN_IS_NEITHER_ON_OFF");
+
+ combination = condition->mutable_combination();
+ combination->set_operation(LogicalOperation::NOR);
+ combination->add_condition("SCREEN_IS_ON");
+ combination->add_condition("SCREEN_IS_OFF");
+
+ return config;
+}
+
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/parse_util.h b/cmds/statsd/src/stats_util.h
index 8b82e7bc15a7..25b9bba56280 100644
--- a/cmds/statsd/src/parse_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -20,6 +20,7 @@
#include "LogReader.h"
#include <log/logprint.h>
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
namespace android {
namespace os {
@@ -29,6 +30,8 @@ EventMetricData parse(log_msg msg);
int getTagId(log_msg msg);
+StatsdConfig buildFakeConfig();
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 3e4ebaf06268..d7702cdd42ad 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -65,7 +65,8 @@ message LogEntryMatcher {
message Combination {
optional LogicalOperation operation = 1;
- repeated LogEntryMatcher matcher = 2;
+
+ repeated string matcher = 2;
}
oneof contents {
SimpleLogEntryMatcher simple_log_entry_matcher = 2;
@@ -122,6 +123,24 @@ message CountMetric {
optional Bucket bucket = 5;
}
+message DurationMetric {
+ optional int64 metric_id = 1;
+
+ enum AggregationType {
+ DURATION_SUM = 1;
+
+ DURATION_MAX_SPARSE = 2;
+ DURATION_MIN_SPARSE = 3;
+ }
+ optional AggregationType type = 2;
+
+ optional string predicate = 3;
+
+ repeated KeyMatcher dimension = 4;
+
+ optional Bucket bucket = 5;
+}
+
message StatsdConfig {
optional int64 config_id = 1;
diff --git a/cmds/statsd/tests/ConditionTracker_test.cpp b/cmds/statsd/tests/ConditionTracker_test.cpp
new file mode 100644
index 000000000000..f8b0fd0796e7
--- /dev/null
+++ b/cmds/statsd/tests/ConditionTracker_test.cpp
@@ -0,0 +1,162 @@
+// 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.
+
+#define LOG_TAG "statsd_test"
+
+#include <gtest/gtest.h>
+#include "../src/condition/condition_util.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+#include <stdio.h>
+#include <vector>
+
+using namespace android::os::statsd;
+using std::vector;
+
+
+#ifdef __ANDROID__
+TEST(ConditionTrackerTest, TestUnknownCondition) {
+ LogicalOperation operation = LogicalOperation::AND;
+
+ vector<int> children;
+ children.push_back(0);
+ children.push_back(1);
+ children.push_back(2);
+
+ vector<ConditionState> conditionResults;
+ conditionResults.push_back(ConditionState::kUnknown);
+ conditionResults.push_back(ConditionState::kFalse);
+ conditionResults.push_back(ConditionState::kTrue);
+
+ EXPECT_EQ(evaluateCombinationCondition(children, operation, conditionResults),
+ ConditionState::kUnknown);
+}
+TEST(ConditionTrackerTest, TestAndCondition) {
+ // Set up the matcher
+ LogicalOperation operation = LogicalOperation::AND;
+
+ vector<int> children;
+ children.push_back(0);
+ children.push_back(1);
+ children.push_back(2);
+
+ vector<ConditionState> conditionResults;
+ conditionResults.push_back(ConditionState::kTrue);
+ conditionResults.push_back(ConditionState::kFalse);
+ conditionResults.push_back(ConditionState::kTrue);
+
+ EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
+
+ conditionResults.clear();
+ conditionResults.push_back(ConditionState::kTrue);
+ conditionResults.push_back(ConditionState::kTrue);
+ conditionResults.push_back(ConditionState::kTrue);
+
+ EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
+}
+
+TEST(ConditionTrackerTest, TestOrCondition) {
+ // Set up the matcher
+ LogicalOperation operation = LogicalOperation::OR;
+
+ vector<int> children;
+ children.push_back(0);
+ children.push_back(1);
+ children.push_back(2);
+
+ vector<ConditionState> conditionResults;
+ conditionResults.push_back(ConditionState::kTrue);
+ conditionResults.push_back(ConditionState::kFalse);
+ conditionResults.push_back(ConditionState::kTrue);
+
+ EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
+
+ conditionResults.clear();
+ conditionResults.push_back(ConditionState::kFalse);
+ conditionResults.push_back(ConditionState::kFalse);
+ conditionResults.push_back(ConditionState::kFalse);
+
+ EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
+}
+
+TEST(ConditionTrackerTest, TestNotCondition) {
+ // Set up the matcher
+ LogicalOperation operation = LogicalOperation::NOT;
+
+ vector<int> children;
+ children.push_back(0);
+
+ vector<ConditionState> conditionResults;
+ conditionResults.push_back(ConditionState::kTrue);
+
+ EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
+
+ conditionResults.clear();
+ conditionResults.push_back(ConditionState::kFalse);
+ EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
+}
+
+TEST(ConditionTrackerTest, TestNandCondition) {
+ // Set up the matcher
+ LogicalOperation operation = LogicalOperation::NAND;
+
+ vector<int> children;
+ children.push_back(0);
+ children.push_back(1);
+
+ vector<ConditionState> conditionResults;
+ conditionResults.push_back(ConditionState::kTrue);
+ conditionResults.push_back(ConditionState::kFalse);
+
+ EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
+
+ conditionResults.clear();
+ conditionResults.push_back(ConditionState::kFalse);
+ conditionResults.push_back(ConditionState::kFalse);
+ EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
+
+ conditionResults.clear();
+ conditionResults.push_back(ConditionState::kTrue);
+ conditionResults.push_back(ConditionState::kTrue);
+ EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
+}
+
+TEST(ConditionTrackerTest, TestNorCondition) {
+ // Set up the matcher
+ LogicalOperation operation = LogicalOperation::NOR;
+
+ vector<int> children;
+ children.push_back(0);
+ children.push_back(1);
+
+ vector<ConditionState> conditionResults;
+ conditionResults.push_back(ConditionState::kTrue);
+ conditionResults.push_back(ConditionState::kFalse);
+
+ EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
+
+ conditionResults.clear();
+ conditionResults.push_back(ConditionState::kFalse);
+ conditionResults.push_back(ConditionState::kFalse);
+ EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
+
+ conditionResults.clear();
+ conditionResults.push_back(ConditionState::kTrue);
+ conditionResults.push_back(ConditionState::kTrue);
+ EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 473704a7e7b9..606980178e2a 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -18,14 +18,15 @@
#include <log/log_event_list.h>
#include <log/log_read.h>
#include <log/logprint.h>
-#include "../src/matchers/LogEntryMatcherManager.h"
-#include "../src/parse_util.h"
+#include "../src/matchers/matcher_util.h"
+#include "../src/stats_util.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include <stdio.h>
using namespace android::os::statsd;
using std::unordered_map;
+using std::vector;
const int kTagIdWakelock = 123;
const int kKeyIdState = 45;
@@ -41,7 +42,7 @@ TEST(LogEntryMatcherTest, TestSimpleMatcher) {
LogEventWrapper wrapper;
wrapper.tagId = kTagIdWakelock;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
}
TEST(LogEntryMatcherTest, TestBoolMatcher) {
@@ -57,13 +58,13 @@ TEST(LogEntryMatcherTest, TestBoolMatcher) {
keyValue->set_eq_bool(true);
wrapper.boolMap[kKeyIdState] = true;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
keyValue->set_eq_bool(false);
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
- wrapper.boolMap[kTagIdWakelock] = false;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ wrapper.boolMap[kKeyIdState] = false;
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
}
TEST(LogEntryMatcherTest, TestStringMatcher) {
@@ -80,7 +81,7 @@ TEST(LogEntryMatcherTest, TestStringMatcher) {
wrapper.strMap[kKeyIdState] = "wakelock_name";
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
}
TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
@@ -96,19 +97,19 @@ TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
keyValue->set_lt_int(10);
wrapper.intMap[kKeyIdState] = 11;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
wrapper.intMap[kKeyIdState] = 10;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
wrapper.intMap[kKeyIdState] = 9;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
keyValue->set_gt_int(10);
wrapper.intMap[kKeyIdState] = 11;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
wrapper.intMap[kKeyIdState] = 10;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
wrapper.intMap[kKeyIdState] = 9;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
}
TEST(LogEntryMatcherTest, TestIntWithEqualityComparisonMatcher) {
@@ -124,19 +125,19 @@ TEST(LogEntryMatcherTest, TestIntWithEqualityComparisonMatcher) {
keyValue->set_lte_int(10);
wrapper.intMap[kKeyIdState] = 11;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
wrapper.intMap[kKeyIdState] = 10;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
wrapper.intMap[kKeyIdState] = 9;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
keyValue->set_gte_int(10);
wrapper.intMap[kKeyIdState] = 11;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
wrapper.intMap[kKeyIdState] = 10;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
wrapper.intMap[kKeyIdState] = 9;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
}
TEST(LogEntryMatcherTest, TestFloatComparisonMatcher) {
@@ -152,15 +153,15 @@ TEST(LogEntryMatcherTest, TestFloatComparisonMatcher) {
keyValue->set_lt_float(10.0);
wrapper.floatMap[kKeyIdState] = 10.1;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
wrapper.floatMap[kKeyIdState] = 9.9;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
keyValue->set_gt_float(10.0);
wrapper.floatMap[kKeyIdState] = 10.1;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, wrapper));
wrapper.floatMap[kKeyIdState] = 9.9;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, wrapper));
}
// Helper for the composite matchers.
@@ -173,141 +174,117 @@ void addSimpleMatcher(SimpleLogEntryMatcher* simpleMatcher, int tag, int key, in
TEST(LogEntryMatcherTest, TestAndMatcher) {
// Set up the matcher
- LogEntryMatcher matcher;
- auto combination = matcher.mutable_combination();
- combination->set_operation(LogicalOperation::AND);
+ LogicalOperation operation = LogicalOperation::AND;
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdState, 3);
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdPackageVersion, 4);
+ vector<int> children;
+ children.push_back(0);
+ children.push_back(1);
+ children.push_back(2);
- LogEventWrapper wrapper;
- wrapper.tagId = kTagIdWakelock;
+ vector<MatchingState> matcherResults;
+ matcherResults.push_back(MatchingState::kMatched);
+ matcherResults.push_back(MatchingState::kNotMatched);
+ matcherResults.push_back(MatchingState::kMatched);
+
+ EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
- wrapper.intMap[1003] = 4;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap.clear();
- wrapper.intMap[1] = 3;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap.clear();
- wrapper.intMap[1] = 3;
- wrapper.intMap[1003] = 4;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ matcherResults.clear();
+ matcherResults.push_back(MatchingState::kMatched);
+ matcherResults.push_back(MatchingState::kMatched);
+ matcherResults.push_back(MatchingState::kMatched);
+
+ EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
}
TEST(LogEntryMatcherTest, TestOrMatcher) {
// Set up the matcher
- LogEntryMatcher matcher;
- auto combination = matcher.mutable_combination();
- combination->set_operation(LogicalOperation::OR);
+ LogicalOperation operation = LogicalOperation::OR;
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdState, 3);
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdPackageVersion, 4);
+ vector<int> children;
+ children.push_back(0);
+ children.push_back(1);
+ children.push_back(2);
- LogEventWrapper wrapper;
- wrapper.tagId = kTagIdWakelock;
+ vector<MatchingState> matcherResults;
+ matcherResults.push_back(MatchingState::kMatched);
+ matcherResults.push_back(MatchingState::kNotMatched);
+ matcherResults.push_back(MatchingState::kMatched);
+
+ EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
- // Don't set any key-value pairs.
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap[1003] = 4;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap.clear();
- wrapper.intMap[1] = 3;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap.clear();
- wrapper.intMap[1] = 3;
- wrapper.intMap[1003] = 4;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
+ matcherResults.clear();
+ matcherResults.push_back(MatchingState::kNotMatched);
+ matcherResults.push_back(MatchingState::kNotMatched);
+ matcherResults.push_back(MatchingState::kNotMatched);
+
+ EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
}
TEST(LogEntryMatcherTest, TestNotMatcher) {
// Set up the matcher
- LogEntryMatcher matcher;
- auto combination = matcher.mutable_combination();
- combination->set_operation(LogicalOperation::NOT);
+ LogicalOperation operation = LogicalOperation::NOT;
- // Define first simpleMatcher
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdState, 3);
+ vector<int> children;
+ children.push_back(0);
- LogEventWrapper wrapper;
- wrapper.tagId = kTagIdWakelock;
+ vector<MatchingState> matcherResults;
+ matcherResults.push_back(MatchingState::kMatched);
+
+ EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
- // Don't set any key-value pairs.
- wrapper.intMap[kKeyIdState] = 3;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ matcherResults.clear();
+ matcherResults.push_back(MatchingState::kNotMatched);
+ EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
}
-TEST(LogEntryMatcherTest, TestNANDMatcher) {
+TEST(LogEntryMatcherTest, TestNandMatcher) {
// Set up the matcher
- LogEntryMatcher matcher;
- auto combination = matcher.mutable_combination();
- combination->set_operation(LogicalOperation::NAND);
+ LogicalOperation operation = LogicalOperation::NAND;
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdState, 3);
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdPackageVersion, 4);
+ vector<int> children;
+ children.push_back(0);
+ children.push_back(1);
- LogEventWrapper wrapper;
- wrapper.tagId = kTagIdWakelock;
+ vector<MatchingState> matcherResults;
+ matcherResults.push_back(MatchingState::kMatched);
+ matcherResults.push_back(MatchingState::kNotMatched);
- // Don't set any key-value pairs.
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap[kKeyIdState] = 3;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap[kKeyIdPackageVersion] = 4;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
-}
+ EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
-TEST(LogEntryMatcherTest, TestNORMatcher) {
- // Set up the matcher
- LogEntryMatcher matcher;
- auto combination = matcher.mutable_combination();
- combination->set_operation(LogicalOperation::NOR);
+ matcherResults.clear();
+ matcherResults.push_back(MatchingState::kNotMatched);
+ matcherResults.push_back(MatchingState::kNotMatched);
+ EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdState, 3);
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdPackageVersion, 4);
+ matcherResults.clear();
+ matcherResults.push_back(MatchingState::kMatched);
+ matcherResults.push_back(MatchingState::kMatched);
+ EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
+}
- LogEventWrapper wrapper;
- wrapper.tagId = kTagIdWakelock;
+TEST(LogEntryMatcherTest, TestNorMatcher) {
+ // Set up the matcher
+ LogicalOperation operation = LogicalOperation::NOR;
- // Don't set any key-value pairs.
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap[kKeyIdState] = 3;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap[kKeyIdPackageVersion] = 4;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
-}
+ vector<int> children;
+ children.push_back(0);
+ children.push_back(1);
-// Tests that a NOT on top of AND is the same as NAND
-TEST(LogEntryMatcherTest, TestMultipleLayerMatcher) {
- LogEntryMatcher matcher;
- auto not_combination = matcher.mutable_combination();
- not_combination->set_operation(LogicalOperation::NOT);
+ vector<MatchingState> matcherResults;
+ matcherResults.push_back(MatchingState::kMatched);
+ matcherResults.push_back(MatchingState::kNotMatched);
- // Now add the AND
- auto combination = not_combination->add_matcher()->mutable_combination();
- combination->set_operation(LogicalOperation::AND);
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdState, 3);
- addSimpleMatcher(combination->add_matcher()->mutable_simple_log_entry_matcher(),
- kTagIdWakelock, kKeyIdPackageVersion, 4);
+ EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
- LogEventWrapper wrapper;
- wrapper.tagId = kTagIdWakelock;
+ matcherResults.clear();
+ matcherResults.push_back(MatchingState::kNotMatched);
+ matcherResults.push_back(MatchingState::kNotMatched);
+ EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
- // Don't set any key-value pairs.
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap[kKeyIdState] = 3;
- EXPECT_TRUE(LogEntryMatcherManager::matches(matcher, wrapper));
- wrapper.intMap[kKeyIdPackageVersion] = 4;
- EXPECT_FALSE(LogEntryMatcherManager::matches(matcher, wrapper));
+ matcherResults.clear();
+ matcherResults.push_back(MatchingState::kMatched);
+ matcherResults.push_back(MatchingState::kMatched);
+ EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
}
#else
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
new file mode 100644
index 000000000000..673c15686f71
--- /dev/null
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -0,0 +1,231 @@
+// 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.
+
+#define LOG_TAG "statsd_test"
+
+#include <gtest/gtest.h>
+#include "../src/condition/ConditionTracker.h"
+#include "../src/matchers/LogMatchingTracker.h"
+#include "../src/metrics/CountMetricProducer.h"
+#include "../src/metrics/MetricProducer.h"
+#include "../src/metrics/metrics_manager_util.h"
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+#include <stdio.h>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+using namespace android::os::statsd;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+// TODO: ADD MORE TEST CASES.
+
+StatsdConfig buildGoodConfig() {
+ StatsdConfig config;
+ config.set_config_id(12345L);
+
+ LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_ON");
+
+ SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_OFF");
+
+ simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
+
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_ON_OR_OFF");
+
+ LogEntryMatcher_Combination* combination = eventMatcher->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher("SCREEN_IS_ON");
+ combination->add_matcher("SCREEN_IS_OFF");
+
+ return config;
+}
+
+StatsdConfig buildCircleMatchers() {
+ StatsdConfig config;
+ config.set_config_id(12345L);
+
+ LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_ON");
+
+ SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_ON_OR_OFF");
+
+ LogEntryMatcher_Combination* combination = eventMatcher->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher("SCREEN_IS_ON");
+ // Circle dependency
+ combination->add_matcher("SCREEN_ON_OR_OFF");
+
+ return config;
+}
+
+StatsdConfig buildMissingMatchers() {
+ StatsdConfig config;
+ config.set_config_id(12345L);
+
+ LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_ON");
+
+ SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_ON_OR_OFF");
+
+ LogEntryMatcher_Combination* combination = eventMatcher->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher("SCREEN_IS_ON");
+ // undefined matcher
+ combination->add_matcher("ABC");
+
+ return config;
+}
+
+StatsdConfig buildCircleConditions() {
+ StatsdConfig config;
+ config.set_config_id(12345L);
+
+ LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_ON");
+
+ SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_OFF");
+
+ simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
+
+ Condition* condition = config.add_condition();
+ condition->set_name("SCREEN_IS_ON");
+ SimpleCondition* simpleCondition = condition->mutable_simple_condition();
+ simpleCondition->set_start("SCREEN_IS_ON");
+ simpleCondition->set_stop("SCREEN_IS_OFF");
+
+ condition = config.add_condition();
+ condition->set_name("SCREEN_IS_EITHER_ON_OFF");
+
+ Condition_Combination* combination = condition->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_condition("SCREEN_IS_ON");
+ combination->add_condition("SCREEN_IS_EITHER_ON_OFF");
+
+ return config;
+}
+
+TEST(MetricsManagerTest, TestGoodConfig) {
+ StatsdConfig config = buildGoodConfig();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+
+ EXPECT_TRUE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
+ allMetricProducers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap));
+}
+
+TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
+ StatsdConfig config = buildCircleMatchers();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+
+ EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
+ allMetricProducers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap));
+}
+
+TEST(MetricsManagerTest, TestMissingMatchers) {
+ StatsdConfig config = buildMissingMatchers();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+
+ EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
+ allMetricProducers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap));
+}
+
+TEST(MetricsManagerTest, TestCircleConditionDependency) {
+ StatsdConfig config = buildCircleConditions();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+
+ EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
+ allMetricProducers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap));
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
new file mode 100644
index 000000000000..b6f14493cb36
--- /dev/null
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -0,0 +1,69 @@
+// 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.
+
+#define LOG_TAG "statsd_test"
+
+#include <gtest/gtest.h>
+#include "../src/UidMap.h"
+#include <stdio.h>
+
+using namespace android;
+using namespace android::os::statsd;
+
+#ifdef __ANDROID__
+const string kApp1 = "app1.sharing.1";
+const string kApp2 = "app2.sharing.1";
+
+TEST(UidMapTest, TestMatching) {
+ UidMap m;
+ vector<int32_t> uids;
+ vector<int32_t> versions;
+ vector<String16> apps;
+
+ uids.push_back(1000);
+ uids.push_back(1000);
+ apps.push_back(String16(kApp1.c_str()));
+ apps.push_back(String16(kApp2.c_str()));
+ versions.push_back(4);
+ versions.push_back(5);
+ m.updateMap(uids, versions, apps);
+ EXPECT_TRUE(m.hasApp(1000, kApp1));
+ EXPECT_TRUE(m.hasApp(1000, kApp2));
+ EXPECT_FALSE(m.hasApp(1000, "not.app"));
+}
+
+TEST(UidMapTest, TestAddAndRemove) {
+ UidMap m;
+ vector<int32_t> uids;
+ vector<int32_t> versions;
+ vector<String16> apps;
+
+ uids.push_back(1000);
+ uids.push_back(1000);
+ apps.push_back(String16(kApp1.c_str()));
+ apps.push_back(String16(kApp2.c_str()));
+ versions.push_back(4);
+ versions.push_back(5);
+ m.updateMap(uids, versions, apps);
+
+ m.updateApp(String16(kApp1.c_str()), 1000, 40);
+ EXPECT_EQ(40, m.getAppVersion(1000, kApp1));
+
+ m.removeApp(String16(kApp1.c_str()), 1000);
+ EXPECT_FALSE(m.hasApp(1000, kApp1));
+ EXPECT_TRUE(m.hasApp(1000, kApp2));
+}
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif \ No newline at end of file
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 8987bc0289b7..23c4166da104 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -73,15 +73,16 @@ public class StatusBarManager {
public static final int DISABLE2_QUICK_SETTINGS = 1;
public static final int DISABLE2_SYSTEM_ICONS = 1 << 1;
public static final int DISABLE2_NOTIFICATION_SHADE = 1 << 2;
+ public static final int DISABLE2_GLOBAL_ACTIONS = 1 << 3;
public static final int DISABLE2_NONE = 0x00000000;
public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS
- | DISABLE2_NOTIFICATION_SHADE;
+ | DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS;
@IntDef(flag = true,
value = {DISABLE2_NONE, DISABLE2_MASK, DISABLE2_QUICK_SETTINGS, DISABLE2_SYSTEM_ICONS,
- DISABLE2_NOTIFICATION_SHADE})
+ DISABLE2_NOTIFICATION_SHADE, DISABLE2_GLOBAL_ACTIONS})
@Retention(RetentionPolicy.SOURCE)
public @interface Disable2Flags {}
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index 3868439f092f..0deb2e13dce0 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -24,7 +24,6 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.ClipData;
import android.content.Context;
-import android.content.Intent;
import android.os.Bundle;
import android.os.PersistableBundle;
@@ -40,16 +39,18 @@ import java.util.List;
* and how to construct them. You will construct these JobInfo objects and pass them to the
* JobScheduler with {@link #schedule(JobInfo)}. When the criteria declared are met, the
* system will execute this job on your application's {@link android.app.job.JobService}.
- * You identify which JobService is meant to execute the logic for your job when you create the
- * JobInfo with
+ * You identify the service component that implements the logic for your job when you
+ * construct the JobInfo using
* {@link android.app.job.JobInfo.Builder#JobInfo.Builder(int,android.content.ComponentName)}.
* </p>
* <p>
- * The framework will be intelligent about when you receive your callbacks, and attempt to batch
- * and defer them as much as possible. Typically if you don't specify a deadline on your job, it
- * can be run at any moment depending on the current state of the JobScheduler's internal queue,
- * however it might be deferred as long as until the next time the device is connected to a power
- * source.
+ * The framework will be intelligent about when it executes jobs, and attempt to batch
+ * and defer them as much as possible. Typically if you don't specify a deadline on a job, it
+ * can be run at any moment depending on the current state of the JobScheduler's internal queue.
+ * <p>
+ * While a job is running, the system holds a wakelock on behalf of your app. For this reason,
+ * you do not need to take any action to guarantee that the device stays awake for the
+ * duration of the job.
* </p>
* <p>You do not
* instantiate this class directly; instead, retrieve it through
@@ -141,30 +142,34 @@ public abstract class JobScheduler {
int userId, String tag);
/**
- * Cancel a job that is pending in the JobScheduler.
- * @param jobId unique identifier for this job. Obtain this value from the jobs returned by
- * {@link #getAllPendingJobs()}.
+ * Cancel the specified job. If the job is currently executing, it is stopped
+ * immediately and the return value from its {@link JobService#onStopJob(JobParameters)}
+ * method is ignored.
+ *
+ * @param jobId unique identifier for the job to be canceled, as supplied to
+ * {@link JobInfo.Builder#JobInfo.Builder(int, android.content.ComponentName)
+ * JobInfo.Builder(int, android.content.ComponentName)}.
*/
public abstract void cancel(int jobId);
/**
- * Cancel all jobs that have been registered with the JobScheduler by this package.
+ * Cancel <em>all</em> jobs that have been scheduled by the calling application.
*/
public abstract void cancelAll();
/**
- * Retrieve all jobs for this package that are pending in the JobScheduler.
+ * Retrieve all jobs that have been scheduled by the calling application.
*
- * @return a list of all the jobs registered by this package that have not
- * yet been executed.
+ * @return a list of all of the app's scheduled jobs. This includes jobs that are
+ * currently started as well as those that are still waiting to run.
*/
public abstract @NonNull List<JobInfo> getAllPendingJobs();
/**
- * Retrieve a specific job for this package that is pending in the
- * JobScheduler.
+ * Look up the description of a scheduled job.
*
- * @return job registered by this package that has not yet been executed.
+ * @return The {@link JobInfo} description of the given scheduled job, or {@code null}
+ * if the supplied job ID does not correspond to any job.
*/
public abstract @Nullable JobInfo getPendingJob(int jobId);
}
diff --git a/core/java/android/app/job/JobService.java b/core/java/android/app/job/JobService.java
index 9096b47b8d4d..69afed205de1 100644
--- a/core/java/android/app/job/JobService.java
+++ b/core/java/android/app/job/JobService.java
@@ -18,16 +18,7 @@ package android.app.job;
import android.app.Service;
import android.content.Intent;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.lang.ref.WeakReference;
/**
* <p>Entry point for the callback from the {@link android.app.job.JobScheduler}.</p>
@@ -55,7 +46,7 @@ public abstract class JobService extends Service {
* </pre>
*
* <p>If a job service is declared in the manifest but not protected with this
- * permission, that service will be ignored by the OS.
+ * permission, that service will be ignored by the system.
*/
public static final String PERMISSION_BIND =
"android.permission.BIND_JOB_SERVICE";
@@ -81,14 +72,36 @@ public abstract class JobService extends Service {
}
/**
- * Override this method with the callback logic for your job. Any such logic needs to be
- * performed on a separate thread, as this function is executed on your application's main
- * thread.
+ * Called to indicate that the job has begun executing. Override this method with the
+ * logic for your job. Like all other component lifecycle callbacks, this method executes
+ * on your application's main thread.
+ * <p>
+ * Return {@code true} from this method if your job needs to continue running. If you
+ * do this, the job remains active until you call
+ * {@link #jobFinished(JobParameters, boolean)} to tell the system that it has completed
+ * its work, or until the job's required constraints are no longer satisfied. For
+ * example, if the job was scheduled using
+ * {@link JobInfo.Builder#setRequiresCharging(boolean) setRequiresCharging(true)},
+ * it will be immediately halted by the system if the user unplugs the device from power,
+ * the job's {@link #onStopJob(JobParameters)} callback will be invoked, and the app
+ * will be expected to shut down all ongoing work connected with that job.
+ * <p>
+ * The system holds a wakelock on behalf of your app as long as your job is executing.
+ * This wakelock is acquired before this method is invoked, and is not released until either
+ * you call {@link #jobFinished(JobParameters, boolean)}, or after the system invokes
+ * {@link #onStopJob(JobParameters)} to notify your job that it is being shut down
+ * prematurely.
+ * <p>
+ * Returning {@code false} from this method means your job is already finished. The
+ * system's wakelock for the job will be released, and {@link #onStopJob(JobParameters)}
+ * will not be invoked.
*
- * @param params Parameters specifying info about this job, including the extras bundle you
- * optionally provided at job-creation time.
- * @return True if your service needs to process the work (on a separate thread). False if
- * there's no more work to be done for this job.
+ * @param params Parameters specifying info about this job, including the optional
+ * extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle).
+ * This object serves to identify this specific running job instance when calling
+ * {@link #jobFinished(JobParameters, boolean)}.
+ * @return {@code true} if your service will continue running, using a separate thread
+ * when appropriate. {@code false} means that this job has completed its work.
*/
public abstract boolean onStartJob(JobParameters params);
@@ -101,37 +114,44 @@ public abstract class JobService extends Service {
* {@link android.app.job.JobInfo.Builder#setRequiredNetworkType(int)}, yet while your
* job was executing the user toggled WiFi. Another example is if you had specified
* {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
- * idle maintenance window. You are solely responsible for the behaviour of your application
- * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
- * immediate repercussion is that the system will cease holding a wakelock for you.</p>
+ * idle maintenance window. You are solely responsible for the behavior of your application
+ * upon receipt of this message; your app will likely start to misbehave if you ignore it.
+ * <p>
+ * Once this method returns, the system releases the wakelock that it is holding on
+ * behalf of the job.</p>
*
- * @param params Parameters specifying info about this job.
- * @return True to indicate to the JobManager whether you'd like to reschedule this job based
- * on the retry criteria provided at job creation-time. False to drop the job. Regardless of
- * the value returned, your job must stop executing.
+ * @param params The parameters identifying this job, as supplied to
+ * the job in the {@link #onStartJob(JobParameters)} callback.
+ * @return {@code true} to indicate to the JobManager whether you'd like to reschedule
+ * this job based on the retry criteria provided at job creation-time; or {@code false}
+ * to end the job entirely. Regardless of the value returned, your job must stop executing.
*/
public abstract boolean onStopJob(JobParameters params);
/**
- * Call this to inform the JobManager you've finished executing. This can be called from any
- * thread, as it will ultimately be run on your application's main thread. When the system
- * receives this message it will release the wakelock being held.
+ * Call this to inform the JobScheduler that the job has finished its work. When the
+ * system receives this message, it releases the wakelock being held for the job.
* <p>
- * You can specify post-execution behaviour to the scheduler here with
- * <code>needsReschedule </code>. This will apply a back-off timer to your job based on
- * the default, or what was set with
- * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}. The original
- * requirements are always honoured even for a backed-off job. Note that a job running in
- * idle mode will not be backed-off. Instead what will happen is the job will be re-added
- * to the queue and re-executed within a future idle maintenance window.
+ * You can request that the job be scheduled again by passing {@code true} as
+ * the <code>wantsReschedule</code> parameter. This will apply back-off policy
+ * for the job; this policy can be adjusted through the
+ * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)} method
+ * when the job is originally scheduled. The job's initial
+ * requirements are preserved when jobs are rescheduled, regardless of backed-off
+ * policy.
+ * <p class="note">
+ * A job running while the device is dozing will not be rescheduled with the normal back-off
+ * policy. Instead, the job will be re-added to the queue and executed again during
+ * a future idle maintenance window.
* </p>
*
- * @param params Parameters specifying system-provided info about this job, this was given to
- * your application in {@link #onStartJob(JobParameters)}.
- * @param needsReschedule True if this job should be rescheduled according to the back-off
- * criteria specified at schedule-time. False otherwise.
+ * @param params The parameters identifying this job, as supplied to
+ * the job in the {@link #onStartJob(JobParameters)} callback.
+ * @param wantsReschedule {@code true} if this job should be rescheduled according
+ * to the back-off criteria specified when it was first scheduled; {@code false}
+ * otherwise.
*/
- public final void jobFinished(JobParameters params, boolean needsReschedule) {
- mEngine.jobFinished(params, needsReschedule);
+ public final void jobFinished(JobParameters params, boolean wantsReschedule) {
+ mEngine.jobFinished(params, wantsReschedule);
}
-} \ No newline at end of file
+}
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index a8b8c4b5cd43..386239cf4f93 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -796,7 +796,7 @@ public class ResourcesImpl {
dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
is.close();
}
- } catch (Exception e) {
+ } catch (Exception | StackOverflowError e) {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
final NotFoundException rnf = new NotFoundException(
"File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index f8f28134063d..daacc4e832f9 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -45,4 +45,20 @@ interface IStatsManager {
* Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
*/
void informPollAlarmFired();
+
+ /**
+ * Inform statsd what the version and package are for each uid. Note that each array should
+ * have the same number of elements, and version[i] and package[i] correspond to uid[i].
+ */
+ oneway void informAllUidData(in int[] uid, in int[] version, in String[] app);
+
+ /**
+ * Inform statsd what the uid and version are for one app that was updated.
+ */
+ oneway void informOnePackage(in String app, in int uid, in int version);
+
+ /**
+ * Inform stats that an app was removed.
+ */
+ oneway void informOnePackageRemoved(in String app, in int uid);
}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 24260c4f32c3..fba358cf4c1b 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -299,7 +299,7 @@ public class DynamicLayout extends Layout
private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
- private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<Builder>(3);
+ private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<>(3);
}
/**
@@ -440,7 +440,7 @@ public class DynamicLayout extends Layout
mEllipsizeAt = null;
}
- mObjects = new PackedObjectVector<Directions>(1);
+ mObjects = new PackedObjectVector<>(1);
// Initial state is a single line with 0 characters (0 to 0), with top at 0 and bottom at
// whatever is natural, and undefined ellipsis.
@@ -1050,7 +1050,7 @@ public class DynamicLayout extends Layout
private static class ChangeWatcher implements TextWatcher, SpanWatcher {
public ChangeWatcher(DynamicLayout layout) {
- mLayout = new WeakReference<DynamicLayout>(layout);
+ mLayout = new WeakReference<>(layout);
}
private void reflow(CharSequence s, int where, int before, int after) {
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 60fff7387c75..ac5c2e926874 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -319,8 +319,6 @@ public abstract class Layout {
private float getJustifyWidth(int lineNum) {
Alignment paraAlign = mAlignment;
- TabStops tabStops = null;
- boolean tabStopsIsInitialized = false;
int left = 0;
int right = mWidth;
@@ -371,10 +369,6 @@ public abstract class Layout {
}
}
- if (getLineContainsTab(lineNum)) {
- tabStops = new TabStops(TAB_INCREMENT, spans);
- }
-
final Alignment align;
if (paraAlign == Alignment.ALIGN_LEFT) {
align = (dir == DIR_LEFT_TO_RIGHT) ? Alignment.ALIGN_NORMAL : Alignment.ALIGN_OPPOSITE;
@@ -1423,7 +1417,6 @@ public abstract class Layout {
float dist = Math.abs(getHorizontal(max, primary) - horiz);
if (dist <= bestdist) {
- bestdist = dist;
best = max;
}
@@ -1570,7 +1563,7 @@ public abstract class Layout {
// XXX: we don't care about tabs
tl.set(mPaint, mText, lineStart, lineEnd, lineDir, directions, false, null);
caret = lineStart + tl.getOffsetToLeftRightOf(caret - lineStart, toLeft);
- tl = TextLine.recycle(tl);
+ TextLine.recycle(tl);
return caret;
}
@@ -1894,10 +1887,7 @@ public abstract class Layout {
int margin = 0;
- boolean isFirstParaLine = lineStart == 0 ||
- spanned.charAt(lineStart - 1) == '\n';
-
- boolean useFirstLineMargin = isFirstParaLine;
+ boolean useFirstLineMargin = lineStart == 0 || spanned.charAt(lineStart - 1) == '\n';
for (int i = 0; i < spans.length; i++) {
if (spans[i] instanceof LeadingMarginSpan2) {
int spStart = spanned.getSpanStart(spans[i]);
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 961cd8eef530..4b6b6ae8bf83 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -433,7 +433,6 @@ public class StaticLayout extends Layout {
* + addStyleRun (a text run, to be measured in native code)
* + addReplacementRun (a replacement run, width is given)
*
- * After measurement, nGetWidths() is valid if the widths are needed (eg for ellipsis).
* Run nComputeLineBreaks() to obtain line breaks for the paragraph.
*
* After all paragraphs, call finish() to release expensive buffers.
@@ -441,8 +440,6 @@ public class StaticLayout extends Layout {
private Pair<String, long[]> getLocaleAndHyphenatorIfChanged(TextPaint paint) {
final LocaleList locales = paint.getTextLocales();
- final String languageTags;
- long[] hyphenators;
if (!locales.equals(mLocales)) {
mLocales = locales;
return new Pair(locales.toLanguageTags(), getHyphenators(locales));
@@ -521,7 +518,7 @@ public class StaticLayout extends Layout {
private LocaleList mLocales;
- private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<Builder>(3);
+ private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<>(3);
}
public StaticLayout(CharSequence source, TextPaint paint,
@@ -866,10 +863,9 @@ public class StaticLayout extends Layout {
spanEndCacheCount++;
}
- nGetWidths(b.mNativePtr, widths);
int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks,
lineBreaks.widths, lineBreaks.ascents, lineBreaks.descents, lineBreaks.flags,
- lineBreaks.breaks.length);
+ lineBreaks.breaks.length, widths);
final int[] breaks = lineBreaks.breaks;
final float[] lineWidths = lineBreaks.widths;
@@ -947,10 +943,10 @@ public class StaticLayout extends Layout {
boolean moreChars = (endPos < bufEnd);
final int ascent = fallbackLineSpacing
- ? Math.min(fmAscent, (int) Math.round(ascents[breakIndex]))
+ ? Math.min(fmAscent, Math.round(ascents[breakIndex]))
: fmAscent;
final int descent = fallbackLineSpacing
- ? Math.max(fmDescent, (int) Math.round(descents[breakIndex]))
+ ? Math.max(fmDescent, Math.round(descents[breakIndex]))
: fmDescent;
v = out(source, here, endPos,
ascent, descent, fmTop, fmBottom,
@@ -1177,7 +1173,7 @@ public class StaticLayout extends Layout {
mWorkPaint.set(paint);
do {
final float ellipsizedWidth = guessEllipsis(text, lineStart, lineEnd, widths,
- widthStart, tempAvail, where, line, textWidth, mWorkPaint, forceEllipsis, dir);
+ widthStart, tempAvail, where, line, mWorkPaint, forceEllipsis, dir);
if (ellipsizedWidth <= avail) {
lineFits = true;
} else {
@@ -1207,7 +1203,7 @@ public class StaticLayout extends Layout {
// This method temporarily modifies the TextPaint passed to it, so the TextPaint passed to it
// should not be accessed while the method is running.
private float guessEllipsis(CharSequence text, int lineStart, int lineEnd, float[] widths,
- int widthStart, float avail, TextUtils.TruncateAt where, int line, float textWidth,
+ int widthStart, float avail, TextUtils.TruncateAt where, int line,
TextPaint paint, boolean forceEllipsis, int dir) {
final int savedHyphenEdit = paint.getHyphenEdit();
paint.setHyphenEdit(0);
@@ -1551,16 +1547,17 @@ public class StaticLayout extends Layout {
@FloatRange(from = 0.0f) float width, @Nullable String languageTags,
@Nullable long[] hyphenators);
- private static native void nGetWidths(long nativePtr, float[] widths);
-
// populates LineBreaks and returns the number of breaks found
//
// the arrays inside the LineBreaks objects are passed in as well
// to reduce the number of JNI calls in the common case where the
// arrays do not have to be resized
+ // The individual character widths will be returned in charWidths. The length of charWidths must
+ // be at least the length of the text.
private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle,
int[] recycleBreaks, float[] recycleWidths, float[] recycleAscents,
- float[] recycleDescents, int[] recycleFlags, int recycleLength);
+ float[] recycleDescents, int[] recycleFlags, int recycleLength,
+ float[] charWidths);
private int mLineCount;
private int mTopPadding, mBottomPadding;
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 2dbff100375a..20c0ed87285a 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -73,7 +73,7 @@ class TextLine {
new SpanSet<ReplacementSpan>(ReplacementSpan.class);
private final DecorationInfo mDecorationInfo = new DecorationInfo();
- private final ArrayList<DecorationInfo> mDecorations = new ArrayList();
+ private final ArrayList<DecorationInfo> mDecorations = new ArrayList<>();
private static final TextLine[] sCached = new TextLine[3];
@@ -340,14 +340,14 @@ class TextLine {
boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
if (inSegment && advance) {
- return h += measureRun(segstart, offset, j, runIsRtl, fmi);
+ return h + measureRun(segstart, offset, j, runIsRtl, fmi);
}
float w = measureRun(segstart, j, j, runIsRtl, fmi);
h += advance ? w : -w;
if (inSegment) {
- return h += measureRun(segstart, offset, j, runIsRtl, null);
+ return h + measureRun(segstart, offset, j, runIsRtl, null);
}
if (codept == '\t') {
@@ -828,14 +828,14 @@ class TextLine {
}
if (info.isUnderlineText) {
final float thickness =
- Math.max(((Paint) wp).getUnderlineThickness(), 1.0f);
+ Math.max(wp.getUnderlineThickness(), 1.0f);
drawStroke(wp, c, wp.getColor(), wp.getUnderlinePosition(), thickness,
decorationXLeft, decorationXRight, y);
}
if (info.isStrikeThruText) {
final float thickness =
- Math.max(((Paint) wp).getStrikeThruThickness(), 1.0f);
+ Math.max(wp.getStrikeThruThickness(), 1.0f);
drawStroke(wp, c, wp.getColor(), wp.getStrikeThruPosition(), thickness,
decorationXLeft, decorationXRight, y);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 36fd991cc78d..439e5e50c8c5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3588,7 +3588,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void updateTimeBasesLocked(boolean unplugged, int screenState, long uptime,
long realtime) {
- final boolean screenOff = isScreenOff(screenState) || isScreenDoze(screenState);
+ final boolean screenOff = !isScreenOn(screenState);
final boolean updateOnBatteryTimeBase = unplugged != mOnBatteryTimeBase.isRunning();
final boolean updateOnBatteryScreenOffTimeBase =
(unplugged && screenOff) != mOnBatteryScreenOffTimeBase.isRunning();
@@ -9463,7 +9463,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
public boolean isScreenOn(int state) {
- return state == Display.STATE_ON;
+ return state == Display.STATE_ON || state == Display.STATE_VR;
}
public boolean isScreenOff(int state) {
diff --git a/core/java/com/android/internal/os/LoggingPrintStream.java b/core/java/com/android/internal/os/LoggingPrintStream.java
index f14394ad09ce..d27874cd3be2 100644
--- a/core/java/com/android/internal/os/LoggingPrintStream.java
+++ b/core/java/com/android/internal/os/LoggingPrintStream.java
@@ -28,12 +28,15 @@ import java.nio.charset.CodingErrorAction;
import java.util.Formatter;
import java.util.Locale;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* A print stream which logs output line by line.
*
* {@hide}
*/
-abstract class LoggingPrintStream extends PrintStream {
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public abstract class LoggingPrintStream extends PrintStream {
private final StringBuilder builder = new StringBuilder();
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 83ffeffd2da3..1f7277a7e98d 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -166,7 +166,7 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
jobject recycle, jintArray recycleBreaks,
jfloatArray recycleWidths, jfloatArray recycleAscents,
jfloatArray recycleDescents, jintArray recycleFlags,
- jint recycleLength) {
+ jint recycleLength, jfloatArray charWidths) {
minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
size_t nBreaks = b->computeBreaks();
@@ -175,6 +175,8 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
recycleFlags, recycleLength, nBreaks, b->getBreaks(), b->getWidths(), b->getAscents(),
b->getDescents(), b->getFlags());
+ env->SetFloatArrayRegion(charWidths, 0, b->size(), b->charWidths());
+
b->finish();
return static_cast<jint>(nBreaks);
@@ -256,11 +258,6 @@ static void nAddReplacementRun(JNIEnv* env, jclass, jlong nativePtr,
b->addReplacement(start, end, width, langTagsString.get(), makeHyphenators(env, hyphenators));
}
-static void nGetWidths(JNIEnv* env, jclass, jlong nativePtr, jfloatArray widths) {
- minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
- env->SetFloatArrayRegion(widths, 0, b->size(), b->charWidths());
-}
-
static const JNINativeMethod gMethods[] = {
// TODO performance: many of these are candidates for fast jni, awaiting guidance
{"nNewBuilder", "()J", (void*) nNewBuilder},
@@ -269,8 +266,7 @@ static const JNINativeMethod gMethods[] = {
{"nSetupParagraph", "(J[CIFIF[IIIIZ[I[I[II)V", (void*) nSetupParagraph},
{"nAddStyleRun", "(JJIIZLjava/lang/String;[J)V", (void*) nAddStyleRun},
{"nAddReplacementRun", "(JIIFLjava/lang/String;[J)V", (void*) nAddReplacementRun},
- {"nGetWidths", "(J[F)V", (void*) nGetWidths},
- {"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[F[F[II)I",
+ {"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[F[F[II[F)I",
(void*) nComputeLineBreaks}
};
diff --git a/core/jni/eventlog_helper.h b/core/jni/eventlog_helper.h
index 1101b837b589..3a05195ebc9e 100644
--- a/core/jni/eventlog_helper.h
+++ b/core/jni/eventlog_helper.h
@@ -17,6 +17,8 @@
#ifndef FRAMEWORKS_BASE_CORE_JNI_EVENTLOG_HELPER_H_
#define FRAMEWORKS_BASE_CORE_JNI_EVENTLOG_HELPER_H_
+#include <memory>
+
#include <fcntl.h>
#include <android-base/macros.h>
@@ -26,6 +28,8 @@
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
#include "core_jni_helpers.h"
#include "jni.h"
@@ -91,20 +95,14 @@ public:
android_log_event_list ctx(tag);
// Don't throw NPE -- I feel like it's sort of mean for a logging function
// to be all crashy if you pass in NULL -- but make the NULL value explicit.
- if (value != NULL) {
- const char *str = env->GetStringUTFChars(value, NULL);
- ctx << str;
- env->ReleaseStringUTFChars(value, str);
- } else {
- ctx << "NULL";
- }
+ ctx << (value != nullptr ? ScopedUtfChars(env, value).c_str() : "NULL");
return ctx.write(LogID);
}
static jint writeEventArray(JNIEnv* env, jobject clazz ATTRIBUTE_UNUSED, jint tag,
jobjectArray value) {
android_log_event_list ctx(tag);
- if (value == NULL) {
+ if (value == nullptr) {
ctx << "[NULL]";
return ctx.write(LogID);
}
@@ -112,26 +110,23 @@ public:
jsize copied = 0, num = env->GetArrayLength(value);
for (; copied < num && copied < 255; ++copied) {
if (ctx.status()) break;
- jobject item = env->GetObjectArrayElement(value, copied);
- if (item == NULL) {
+ ScopedLocalRef<jobject> item(env, env->GetObjectArrayElement(value, copied));
+ if (item == nullptr) {
ctx << "NULL";
- } else if (env->IsInstanceOf(item, gStringClass)) {
- const char *str = env->GetStringUTFChars((jstring) item, NULL);
- ctx << str;
- env->ReleaseStringUTFChars((jstring) item, str);
- } else if (env->IsInstanceOf(item, gIntegerClass)) {
- ctx << (int32_t)env->GetIntField(item, gIntegerValueID);
- } else if (env->IsInstanceOf(item, gLongClass)) {
- ctx << (int64_t)env->GetLongField(item, gLongValueID);
- } else if (env->IsInstanceOf(item, gFloatClass)) {
- ctx << (float)env->GetFloatField(item, gFloatValueID);
+ } else if (env->IsInstanceOf(item.get(), gStringClass)) {
+ ctx << ScopedUtfChars(env, (jstring) item.get()).c_str();
+ } else if (env->IsInstanceOf(item.get(), gIntegerClass)) {
+ ctx << (int32_t)env->GetIntField(item.get(), gIntegerValueID);
+ } else if (env->IsInstanceOf(item.get(), gLongClass)) {
+ ctx << (int64_t)env->GetLongField(item.get(), gLongValueID);
+ } else if (env->IsInstanceOf(item.get(), gFloatClass)) {
+ ctx << (float)env->GetFloatField(item.get(), gFloatValueID);
} else {
jniThrowException(env,
"java/lang/IllegalArgumentException",
"Invalid payload item type");
return -1;
}
- env->DeleteLocalRef(item);
}
return ctx.write(LogID);
}
@@ -140,39 +135,37 @@ public:
readEvents(env, loggerMode, nullptr, startTime, out);
}
- static void readEvents(JNIEnv* env, int loggerMode, jintArray tags, jlong startTime,
+ static void readEvents(JNIEnv* env, int loggerMode, jintArray jTags, jlong startTime,
jobject out) {
- struct logger_list *logger_list;
+ std::unique_ptr<struct logger_list, decltype(&android_logger_list_close)> logger_list(
+ nullptr, android_logger_list_close);
if (startTime) {
- logger_list = android_logger_list_alloc_time(loggerMode,
- log_time(startTime / NS_PER_SEC, startTime % NS_PER_SEC), 0);
+ logger_list.reset(android_logger_list_alloc_time(loggerMode,
+ log_time(startTime / NS_PER_SEC, startTime % NS_PER_SEC), 0));
} else {
- logger_list = android_logger_list_alloc(loggerMode, 0, 0);
+ logger_list.reset(android_logger_list_alloc(loggerMode, 0, 0));
}
if (!logger_list) {
jniThrowIOException(env, errno);
return;
}
- if (!android_logger_open(logger_list, LogID)) {
+ if (!android_logger_open(logger_list.get(), LogID)) {
jniThrowIOException(env, errno);
- android_logger_list_free(logger_list);
return;
}
- jsize tagLength = 0;
- jint *tagValues = nullptr;
- if (tags != nullptr) {
- tagLength = env->GetArrayLength(tags);
- tagValues = env->GetIntArrayElements(tags, NULL);
+ ScopedIntArrayRO tags(env);
+ if (jTags != nullptr) {
+ tags.reset(jTags);
}
while (1) {
log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
+ int ret = android_logger_list_read(logger_list.get(), &log_msg);
if (ret == 0) {
- break;
+ return;
}
if (ret < 0) {
if (ret == -EINTR) {
@@ -183,7 +176,7 @@ public:
} else if (ret != -EAGAIN) {
jniThrowIOException(env, -ret); // Will throw on return
}
- break;
+ return;
}
if (log_msg.id() != LogID) {
@@ -192,10 +185,10 @@ public:
int32_t tag = * (int32_t *) log_msg.msg();
- if (tags != nullptr) {
+ if (jTags != nullptr) {
bool found = false;
- for (int i = 0; !found && i < tagLength; ++i) {
- found = (tag == tagValues[i]);
+ for (size_t i = 0; !found && i < tags.size(); ++i) {
+ found = (tag == tags[i]);
}
if (!found) {
continue;
@@ -203,33 +196,27 @@ public:
}
jsize len = ret;
- jbyteArray array = env->NewByteArray(len);
- if (array == NULL) {
- break;
+ ScopedLocalRef<jbyteArray> array(env, env->NewByteArray(len));
+ if (array == nullptr) {
+ return;
}
- jbyte *bytes = env->GetByteArrayElements(array, NULL);
- memcpy(bytes, log_msg.buf, len);
- env->ReleaseByteArrayElements(array, bytes, 0);
+ {
+ ScopedByteArrayRW bytes(env, array.get());
+ memcpy(bytes.get(), log_msg.buf, len);
+ }
- jobject event = env->NewObject(gEventClass, gEventInitID, array);
- if (event == NULL) {
- break;
+ ScopedLocalRef<jobject> event(env,
+ env->NewObject(gEventClass, gEventInitID, array.get()));
+ if (event == nullptr) {
+ return;
}
- env->CallBooleanMethod(out, gCollectionAddID, event);
- env->DeleteLocalRef(event);
- env->DeleteLocalRef(array);
+ env->CallBooleanMethod(out, gCollectionAddID, event.get());
if (env->ExceptionCheck() == JNI_TRUE) {
- break;
+ return;
}
}
-
- android_logger_list_close(logger_list);
-
- if (tags != nullptr) {
- env->ReleaseIntArrayElements(tags, tagValues, 0);
- }
}
private:
diff --git a/core/res/res/values-mcc001-mnc01/strings.xml b/core/res/res/values-mcc001-mnc01/strings.xml
new file mode 100644
index 000000000000..96af975b50b5
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc030/strings.xml b/core/res/res/values-mcc310-mnc030/strings.xml
index a3fea29070f5..6a404d5cee5f 100644
--- a/core/res/res/values-mcc310-mnc030/strings.xml
+++ b/core/res/res/values-mcc310-mnc030/strings.xml
@@ -20,4 +20,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
<string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc150/strings.xml b/core/res/res/values-mcc310-mnc150/strings.xml
new file mode 100644
index 000000000000..96af975b50b5
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc170/strings.xml b/core/res/res/values-mcc310-mnc170/strings.xml
index a3fea29070f5..6a404d5cee5f 100644
--- a/core/res/res/values-mcc310-mnc170/strings.xml
+++ b/core/res/res/values-mcc310-mnc170/strings.xml
@@ -20,4 +20,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
<string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc280/strings.xml b/core/res/res/values-mcc310-mnc280/strings.xml
index a3fea29070f5..6a404d5cee5f 100644
--- a/core/res/res/values-mcc310-mnc280/strings.xml
+++ b/core/res/res/values-mcc310-mnc280/strings.xml
@@ -20,4 +20,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
<string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc410/strings.xml b/core/res/res/values-mcc310-mnc410/strings.xml
index a3fea29070f5..6a404d5cee5f 100644
--- a/core/res/res/values-mcc310-mnc410/strings.xml
+++ b/core/res/res/values-mcc310-mnc410/strings.xml
@@ -20,4 +20,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
<string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc560/strings.xml b/core/res/res/values-mcc310-mnc560/strings.xml
index a3fea29070f5..6a404d5cee5f 100644
--- a/core/res/res/values-mcc310-mnc560/strings.xml
+++ b/core/res/res/values-mcc310-mnc560/strings.xml
@@ -20,4 +20,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
<string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc950/strings.xml b/core/res/res/values-mcc310-mnc950/strings.xml
index a3fea29070f5..6a404d5cee5f 100644
--- a/core/res/res/values-mcc310-mnc950/strings.xml
+++ b/core/res/res/values-mcc310-mnc950/strings.xml
@@ -20,4 +20,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
<string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
</resources>
diff --git a/core/res/res/values-mcc311-mnc180/strings.xml b/core/res/res/values-mcc311-mnc180/strings.xml
index a3fea29070f5..6a404d5cee5f 100644
--- a/core/res/res/values-mcc311-mnc180/strings.xml
+++ b/core/res/res/values-mcc311-mnc180/strings.xml
@@ -20,4 +20,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
<string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
</resources>
diff --git a/core/res/res/values-mcc312-mnc670/strings.xml b/core/res/res/values-mcc312-mnc670/strings.xml
new file mode 100644
index 000000000000..96af975b50b5
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100/strings.xml b/core/res/res/values-mcc313-mnc100/strings.xml
new file mode 100644
index 000000000000..96af975b50b5
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_illegal_me">Phone not allowed MM#6</string>
+</resources>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index dbc9e5d55e37..15eab1f72aab 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -36,7 +36,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
ub-uiautomator \
platform-test-annotations \
compatibility-device-util \
- truth-prebuilt
+ truth-prebuilt \
+ print-test-util-lib
LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy
LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index ac5d224c9030..9c0543b18f8b 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -102,6 +102,7 @@
<!-- os storage test permissions -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.ASEC_ACCESS" />
+ <uses-permission android:name="android.permission.ASEC_ACCESS" />
<uses-permission android:name="android.permission.ASEC_CREATE" />
<uses-permission android:name="android.permission.ASEC_DESTROY" />
<uses-permission android:name="android.permission.ASEC_MOUNT_UNMOUNT" />
@@ -1345,10 +1346,12 @@
</intent-filter>
</activity>
- <activity android:name="android.print.PrintTestActivity"/>
+ <activity
+ android:name="android.print.test.PrintDocumentActivity"
+ android:theme="@style/Theme" />
<service
- android:name="android.print.mockservice.MockPrintService"
+ android:name="android.print.test.services.FirstPrintService"
android:permission="android.permission.BIND_PRINT_SERVICE">
<intent-filter>
<action android:name="android.printservice.PrintService" />
@@ -1360,9 +1363,10 @@
</service>
<activity
- android:name="android.print.mockservice.SettingsActivity"
+ android:name="android.print.test.services.SettingsActivity"
android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
- android:exported="true">
+ android:exported="true"
+ android:theme="@style/Theme">
</activity>
<activity
diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
deleted file mode 100644
index a70c6046b230..000000000000
--- a/core/tests/coretests/src/android/print/BasePrintTest.java
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.print;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.CancellationSignal;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
-import android.print.mockservice.PrintServiceCallbacks;
-import android.print.mockservice.PrinterDiscoverySessionCallbacks;
-import android.print.mockservice.StubbablePrinterDiscoverySession;
-import android.printservice.CustomPrinterIconCallback;
-import android.printservice.PrintJob;
-import android.printservice.PrintService;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.uiautomator.UiDevice;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.mockito.stubbing.Answer;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This is the base class for print tests.
- */
-abstract class BasePrintTest {
- protected static final long OPERATION_TIMEOUT = 30000;
- private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success";
- private static final int CURRENT_USER_ID = -2; // Mirrors UserHandle.USER_CURRENT
-
- private android.print.PrintJob mPrintJob;
-
- private CallCounter mStartCallCounter;
- private CallCounter mStartSessionCallCounter;
-
- private static Instrumentation sInstrumentation;
- private static UiDevice sUiDevice;
-
- @Rule
- public ActivityTestRule<PrintTestActivity> mActivityRule =
- new ActivityTestRule<>(PrintTestActivity.class, false, true);
-
- /**
- * {@link Runnable} that can throw and {@link Exception}
- */
- interface Invokable {
- /**
- * Execute the invokable
- *
- * @throws Exception
- */
- void run() throws Exception;
- }
-
- /**
- * Assert that the invokable throws an expectedException
- *
- * @param invokable The {@link Invokable} to run
- * @param expectedClass The {@link Exception} that is supposed to be thrown
- */
- void assertException(Invokable invokable, Class<? extends Exception> expectedClass)
- throws Exception {
- try {
- invokable.run();
- } catch (Exception e) {
- if (e.getClass().isAssignableFrom(expectedClass)) {
- return;
- } else {
- throw e;
- }
- }
-
- throw new AssertionError("No exception thrown");
- }
-
- /**
- * Return the UI device
- *
- * @return the UI device
- */
- public UiDevice getUiDevice() {
- return sUiDevice;
- }
-
- protected static Instrumentation getInstrumentation() {
- return sInstrumentation;
- }
-
- @BeforeClass
- public static void setUpClass() throws Exception {
- sInstrumentation = InstrumentationRegistry.getInstrumentation();
- assumeTrue(sInstrumentation.getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_PRINTING));
-
- sUiDevice = UiDevice.getInstance(sInstrumentation);
-
- // Make sure we start with a clean slate.
- clearPrintSpoolerData();
-
- // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
- // Dexmaker is used by mockito.
- System.setProperty("dexmaker.dexcache", getInstrumentation()
- .getTargetContext().getCacheDir().getPath());
- }
-
- @Before
- public void initCounters() throws Exception {
- // Initialize the latches.
- mStartCallCounter = new CallCounter();
- mStartSessionCallCounter = new CallCounter();
- }
-
- @Before
- public void unlockScreen() throws Exception {
- // Unlock screen.
- runShellCommand(getInstrumentation(), "input keyevent KEYCODE_WAKEUP");
- runShellCommand(getInstrumentation(), "wm dismiss-keyguard");
- }
-
- @After
- public void exitActivities() throws Exception {
- // Exit print spooler
- getUiDevice().pressBack();
- getUiDevice().pressBack();
- }
-
- protected android.print.PrintJob print(@NonNull final PrintDocumentAdapter adapter,
- final PrintAttributes attributes) {
- // Initiate printing as if coming from the app.
- getInstrumentation().runOnMainSync(() -> {
- PrintManager printManager = (PrintManager) getActivity()
- .getSystemService(Context.PRINT_SERVICE);
- mPrintJob = printManager.print("Print job", adapter, attributes);
- });
-
- return mPrintJob;
- }
-
- protected void onStartCalled() {
- mStartCallCounter.call();
- }
-
- protected void onPrinterDiscoverySessionStartCalled() {
- mStartSessionCallCounter.call();
- }
-
- protected void waitForPrinterDiscoverySessionStartCallbackCalled() {
- waitForCallbackCallCount(mStartSessionCallCounter, 1,
- "Did not get expected call to onStartPrinterDiscoverySession.");
- }
-
- protected void waitForStartAdapterCallbackCalled() {
- waitForCallbackCallCount(mStartCallCounter, 1, "Did not get expected call to start.");
- }
-
- private static void waitForCallbackCallCount(CallCounter counter, int count, String message) {
- try {
- counter.waitForCount(count, OPERATION_TIMEOUT);
- } catch (TimeoutException te) {
- fail(message);
- }
- }
-
- protected PrintTestActivity getActivity() {
- return mActivityRule.getActivity();
- }
-
- public static String runShellCommand(Instrumentation instrumentation, String cmd)
- throws IOException {
- ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
- byte[] buf = new byte[512];
- int bytesRead;
- FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
- StringBuilder stdout = new StringBuilder();
- while ((bytesRead = fis.read(buf)) != -1) {
- stdout.append(new String(buf, 0, bytesRead));
- }
- fis.close();
- return stdout.toString();
- }
-
- protected static void clearPrintSpoolerData() throws Exception {
- assertTrue("failed to clear print spooler data",
- runShellCommand(getInstrumentation(), String.format(
- "pm clear --user %d %s", CURRENT_USER_ID,
- PrintManager.PRINT_SPOOLER_PACKAGE_NAME))
- .contains(PM_CLEAR_SUCCESS_OUTPUT));
- }
-
- @SuppressWarnings("unchecked")
- protected PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
- Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery,
- Answer<Void> onValidatePrinters, Answer<Void> onStartPrinterStateTracking,
- Answer<Void> onRequestCustomPrinterIcon, Answer<Void> onStopPrinterStateTracking,
- Answer<Void> onDestroy) {
- PrinterDiscoverySessionCallbacks callbacks = mock(PrinterDiscoverySessionCallbacks.class);
-
- doCallRealMethod().when(callbacks).setSession(any(StubbablePrinterDiscoverySession.class));
- when(callbacks.getSession()).thenCallRealMethod();
-
- if (onStartPrinterDiscovery != null) {
- doAnswer(onStartPrinterDiscovery).when(callbacks).onStartPrinterDiscovery(
- any(List.class));
- }
- if (onStopPrinterDiscovery != null) {
- doAnswer(onStopPrinterDiscovery).when(callbacks).onStopPrinterDiscovery();
- }
- if (onValidatePrinters != null) {
- doAnswer(onValidatePrinters).when(callbacks).onValidatePrinters(
- any(List.class));
- }
- if (onStartPrinterStateTracking != null) {
- doAnswer(onStartPrinterStateTracking).when(callbacks).onStartPrinterStateTracking(
- any(PrinterId.class));
- }
- if (onRequestCustomPrinterIcon != null) {
- doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
- any(PrinterId.class), any(CancellationSignal.class),
- any(CustomPrinterIconCallback.class));
- }
- if (onStopPrinterStateTracking != null) {
- doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
- any(PrinterId.class));
- }
- if (onDestroy != null) {
- doAnswer(onDestroy).when(callbacks).onDestroy();
- }
-
- return callbacks;
- }
-
- protected PrintServiceCallbacks createMockPrintServiceCallbacks(
- Answer<PrinterDiscoverySessionCallbacks> onCreatePrinterDiscoverySessionCallbacks,
- Answer<Void> onPrintJobQueued, Answer<Void> onRequestCancelPrintJob) {
- final PrintServiceCallbacks service = mock(PrintServiceCallbacks.class);
-
- doCallRealMethod().when(service).setService(any(PrintService.class));
- when(service.getService()).thenCallRealMethod();
-
- if (onCreatePrinterDiscoverySessionCallbacks != null) {
- doAnswer(onCreatePrinterDiscoverySessionCallbacks).when(service)
- .onCreatePrinterDiscoverySessionCallbacks();
- }
- if (onPrintJobQueued != null) {
- doAnswer(onPrintJobQueued).when(service).onPrintJobQueued(any(PrintJob.class));
- }
- if (onRequestCancelPrintJob != null) {
- doAnswer(onRequestCancelPrintJob).when(service).onRequestCancelPrintJob(
- any(PrintJob.class));
- }
-
- return service;
- }
-
- private static final class CallCounter {
- private final Object mLock = new Object();
-
- private int mCallCount;
-
- public void call() {
- synchronized (mLock) {
- mCallCount++;
- mLock.notifyAll();
- }
- }
-
- int getCallCount() {
- synchronized (mLock) {
- return mCallCount;
- }
- }
-
- public void waitForCount(int count, long timeoutMillis) throws TimeoutException {
- synchronized (mLock) {
- final long startTimeMillis = SystemClock.uptimeMillis();
- while (mCallCount < count) {
- try {
- final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
- final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
- if (remainingTimeMillis <= 0) {
- throw new TimeoutException();
- }
- mLock.wait(timeoutMillis);
- } catch (InterruptedException ie) {
- /* ignore */
- }
- }
- }
- }
- }
-}
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index 45e3f679fe55..5d12f7e43558 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -16,6 +16,8 @@
package android.print;
+import static android.print.test.Utils.assertException;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -33,10 +35,11 @@ import android.os.UserHandle;
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
-import android.print.mockservice.MockPrintService;
-import android.print.mockservice.PrintServiceCallbacks;
-import android.print.mockservice.PrinterDiscoverySessionCallbacks;
-import android.print.mockservice.StubbablePrinterDiscoverySession;
+import android.print.test.BasePrintTest;
+import android.print.test.services.FirstPrintService;
+import android.print.test.services.PrintServiceCallbacks;
+import android.print.test.services.PrinterDiscoverySessionCallbacks;
+import android.print.test.services.StubbablePrinterDiscoverySession;
import android.printservice.recommendation.IRecommendationsChangeListener;
import android.support.test.filters.LargeTest;
import android.support.test.filters.MediumTest;
@@ -149,7 +152,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
session.addPrinters(printers);
}
- onPrinterDiscoverySessionStartCalled();
+ onPrinterDiscoverySessionCreateCalled();
return null;
}, null, null, null, null, null, null),
null, null);
@@ -200,13 +203,18 @@ public class IPrintManagerParametersTest extends BasePrintTest {
}
private void startPrinting() {
- mGoodPrintJob = print(createMockAdapter(), null);
+ mGoodPrintJob = print(createMockAdapter(), (PrintAttributes) null);
// Wait for PrintActivity to be ready
- waitForStartAdapterCallbackCalled();
+ waitForAdapterStartCallbackCalled();
// Wait for printer discovery session to be ready
- waitForPrinterDiscoverySessionStartCallbackCalled();
+ waitForPrinterDiscoverySessionCreateCallbackCalled();
+ }
+
+ private void endPrinting() {
+ getUiDevice().pressBack();
+ getUiDevice().pressBack();
}
/**
@@ -220,7 +228,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
@Before
public void setUpMockService() throws Exception {
- MockPrintService.setCallbacks(createMockCallbacks());
+ FirstPrintService.setCallbacks(createMockCallbacks());
mIPrintManager = IPrintManager.Stub
.asInterface(ServiceManager.getService(Context.PRINT_SERVICE));
@@ -231,7 +239,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@LargeTest
@Test
- public void testGetPrintJobInfo() throws Exception {
+ public void testGetPrintJobInfo() throws Throwable {
startPrinting();
assertEquals(mGoodPrintJob.getId(), mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(),
@@ -244,6 +252,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
SecurityException.class);
// Cannot test bad user Id as these tests are allowed to call across users
+
+ endPrinting();
}
/**
@@ -251,7 +261,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@LargeTest
@Test
- public void testGetPrintJobInfos() throws Exception {
+ public void testGetPrintJobInfos() throws Throwable {
startPrinting();
List<PrintJobInfo> infos = mIPrintManager.getPrintJobInfos(mAppId, mUserId);
@@ -269,6 +279,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
SecurityException.class);
// Cannot test bad user Id as these tests are allowed to call across users
+
+ endPrinting();
}
/**
@@ -276,7 +288,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@LargeTest
@Test
- public void testPrint() throws Exception {
+ public void testPrint() throws Throwable {
final String name = "dummy print job";
final IPrintDocumentAdapter adapter = new PrintManager
@@ -303,6 +315,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
getActivity().getPackageName(), BAD_APP_ID, mUserId), SecurityException.class);
// Cannot test bad user Id as these tests are allowed to call across users
+
+ endPrinting();
}
/**
@@ -310,7 +324,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@LargeTest
@Test
- public void testCancelPrintJob() throws Exception {
+ public void testCancelPrintJob() throws Throwable {
startPrinting();
// Invalid print jobs IDs do not produce an exception
@@ -325,6 +339,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
// Must be last as otherwise mGoodPrintJob will not be good anymore
mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
+
+ endPrinting();
}
/**
@@ -332,7 +348,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@LargeTest
@Test
- public void testRestartPrintJob() throws Exception {
+ public void testRestartPrintJob() throws Throwable {
startPrinting();
mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
@@ -346,6 +362,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
SecurityException.class);
// Cannot test bad user Id as these tests are allowed to call across users
+
+ endPrinting();
}
/**
@@ -353,7 +371,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testAddPrintJobStateChangeListener() throws Exception {
+ @NoActivity
+ public void testAddPrintJobStateChangeListener() throws Throwable {
final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
@@ -373,7 +392,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testRemovePrintJobStateChangeListener() throws Exception {
+ @NoActivity
+ public void testRemovePrintJobStateChangeListener() throws Throwable {
final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
@@ -394,7 +414,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testAddPrintServicesChangeListener() throws Exception {
+ @NoActivity
+ public void testAddPrintServicesChangeListener() throws Throwable {
final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener();
assertException(() -> mIPrintManager.addPrintServicesChangeListener(listener, mUserId),
@@ -411,7 +432,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testRemovePrintServicesChangeListener() throws Exception {
+ @NoActivity
+ public void testRemovePrintServicesChangeListener() throws Throwable {
final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener();
assertException(() -> mIPrintManager.removePrintServicesChangeListener(listener, mUserId),
@@ -426,7 +448,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testGetPrintServices() throws Exception {
+ @NoActivity
+ public void testGetPrintServices() throws Throwable {
assertException(() -> mIPrintManager.getPrintServices(PrintManager.ALL_SERVICES, mUserId),
SecurityException.class);
@@ -444,7 +467,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testSetPrintServiceEnabled() throws Exception {
+ @NoActivity
+ public void testSetPrintServiceEnabled() throws Throwable {
assertException(
() -> mIPrintManager.setPrintServiceEnabled(new ComponentName("bad", "name"), true,
mUserId), SecurityException.class);
@@ -460,7 +484,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testAddPrintServiceRecommendationsChangeListener() throws Exception {
+ @NoActivity
+ public void testAddPrintServiceRecommendationsChangeListener() throws Throwable {
final IRecommendationsChangeListener listener =
createMockIPrintServiceRecommendationsChangeListener();
@@ -479,7 +504,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testRemovePrintServiceRecommendationsChangeListener() throws Exception {
+ @NoActivity
+ public void testRemovePrintServiceRecommendationsChangeListener() throws Throwable {
final IRecommendationsChangeListener listener =
createMockIPrintServiceRecommendationsChangeListener();
@@ -498,7 +524,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testGetPrintServiceRecommendations() throws Exception {
+ @NoActivity
+ public void testGetPrintServiceRecommendations() throws Throwable {
assertException(() -> mIPrintManager.getPrintServiceRecommendations(mUserId),
SecurityException.class);
@@ -510,7 +537,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testCreatePrinterDiscoverySession() throws Exception {
+ @NoActivity
+ public void testCreatePrinterDiscoverySession() throws Throwable {
final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
mIPrintManager.createPrinterDiscoverySession(listener, mUserId);
@@ -533,7 +561,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@LargeTest
@Test
- public void testStartPrinterDiscovery() throws Exception {
+ public void testStartPrinterDiscovery() throws Throwable {
startPrinting();
final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
@@ -562,6 +590,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
NullPointerException.class);
// Cannot test bad user Id as these tests are allowed to call across users
+
+ endPrinting();
}
/**
@@ -569,7 +599,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testStopPrinterDiscovery() throws Exception {
+ @NoActivity
+ public void testStopPrinterDiscovery() throws Throwable {
final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
@@ -590,7 +621,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@LargeTest
@Test
- public void testValidatePrinters() throws Exception {
+ public void testValidatePrinters() throws Throwable {
startPrinting();
final List<PrinterId> goodPrinters = new ArrayList<>();
@@ -617,6 +648,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
NullPointerException.class);
// Cannot test bad user Id as these tests are allowed to call across users
+
+ endPrinting();
}
/**
@@ -624,7 +657,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@LargeTest
@Test
- public void testStartPrinterStateTracking() throws Exception {
+ public void testStartPrinterStateTracking() throws Throwable {
startPrinting();
mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
@@ -636,6 +669,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
NullPointerException.class);
// Cannot test bad user Id as these tests are allowed to call across users
+
+ endPrinting();
}
/**
@@ -643,7 +678,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@LargeTest
@Test
- public void testGetCustomPrinterIcon() throws Exception {
+ public void testGetCustomPrinterIcon() throws Throwable {
startPrinting();
mIPrintManager.getCustomPrinterIcon(mGoodPrinterId, mUserId);
@@ -655,6 +690,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
NullPointerException.class);
// Cannot test bad user Id as these tests are allowed to call across users
+
+ endPrinting();
}
/**
@@ -662,7 +699,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@LargeTest
@Test
- public void testStopPrinterStateTracking() throws Exception {
+ public void testStopPrinterStateTracking() throws Throwable {
startPrinting();
mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
@@ -679,6 +716,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
NullPointerException.class);
// Cannot test bad user Id as these tests are allowed to call across users
+
+ endPrinting();
}
/**
@@ -686,7 +725,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
@MediumTest
@Test
- public void testDestroyPrinterDiscoverySession() throws Exception {
+ @NoActivity
+ public void testDestroyPrinterDiscoverySession() throws Throwable {
final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
mIPrintManager.createPrinterDiscoverySession(listener, mUserId);
diff --git a/core/tests/coretests/src/android/print/mockservice/MockPrintService.java b/core/tests/coretests/src/android/print/mockservice/MockPrintService.java
deleted file mode 100644
index 9c11c22282d7..000000000000
--- a/core/tests/coretests/src/android/print/mockservice/MockPrintService.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.print.mockservice;
-
-public class MockPrintService extends StubbablePrintService {
-
- private static final Object sLock = new Object();
-
- private static PrintServiceCallbacks sCallbacks;
-
- public static void setCallbacks(PrintServiceCallbacks callbacks) {
- synchronized (sLock) {
- sCallbacks = callbacks;
- }
- }
-
- @Override
- protected PrintServiceCallbacks getCallbacks() {
- synchronized (sLock) {
- if (sCallbacks != null) {
- sCallbacks.setService(this);
- }
- return sCallbacks;
- }
- }
-}
diff --git a/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java
deleted file mode 100644
index 4e892072f0cb..000000000000
--- a/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.print.mockservice;
-
-import android.printservice.PrintJob;
-import android.printservice.PrintService;
-
-public abstract class PrintServiceCallbacks {
-
- private PrintService mService;
-
- public PrintService getService() {
- return mService;
- }
-
- public void setService(PrintService service) {
- mService = service;
- }
-
- public abstract PrinterDiscoverySessionCallbacks onCreatePrinterDiscoverySessionCallbacks();
-
- public abstract void onRequestCancelPrintJob(PrintJob printJob);
-
- public abstract void onPrintJobQueued(PrintJob printJob);
-}
diff --git a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
deleted file mode 100644
index be002e29ff68..000000000000
--- a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.print.mockservice;
-
-import android.os.CancellationSignal;
-import android.print.PrinterId;
-import android.printservice.CustomPrinterIconCallback;
-
-import java.util.List;
-
-public abstract class PrinterDiscoverySessionCallbacks {
-
- private StubbablePrinterDiscoverySession mSession;
-
- public void setSession(StubbablePrinterDiscoverySession session) {
- mSession = session;
- }
-
- public StubbablePrinterDiscoverySession getSession() {
- return mSession;
- }
-
- public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
-
- public abstract void onStopPrinterDiscovery();
-
- public abstract void onValidatePrinters(List<PrinterId> printerIds);
-
- public abstract void onStartPrinterStateTracking(PrinterId printerId);
-
- public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
- CancellationSignal cancellationSignal, CustomPrinterIconCallback callback);
-
- public abstract void onStopPrinterStateTracking(PrinterId printerId);
-
- public abstract void onDestroy();
-}
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java
deleted file mode 100644
index b58b27350c28..000000000000
--- a/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.print.mockservice;
-
-import android.printservice.PrintJob;
-import android.printservice.PrintService;
-import android.printservice.PrinterDiscoverySession;
-
-public abstract class StubbablePrintService extends PrintService {
-
- @Override
- public PrinterDiscoverySession onCreatePrinterDiscoverySession() {
- PrintServiceCallbacks callbacks = getCallbacks();
- if (callbacks != null) {
- return new StubbablePrinterDiscoverySession(this,
- getCallbacks().onCreatePrinterDiscoverySessionCallbacks());
- }
- return null;
- }
-
- @Override
- public void onRequestCancelPrintJob(PrintJob printJob) {
- PrintServiceCallbacks callbacks = getCallbacks();
- if (callbacks != null) {
- callbacks.onRequestCancelPrintJob(printJob);
- }
- }
-
- @Override
- public void onPrintJobQueued(PrintJob printJob) {
- PrintServiceCallbacks callbacks = getCallbacks();
- if (callbacks != null) {
- callbacks.onPrintJobQueued(printJob);
- }
- }
-
- protected abstract PrintServiceCallbacks getCallbacks();
-}
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
deleted file mode 100644
index f3a5373722cc..000000000000
--- a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.print.mockservice;
-
-import android.support.annotation.NonNull;
-import android.os.CancellationSignal;
-import android.print.PrinterId;
-import android.printservice.CustomPrinterIconCallback;
-import android.printservice.PrintService;
-import android.printservice.PrinterDiscoverySession;
-
-import java.util.List;
-
-public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession {
- private final PrintService mService;
- private final PrinterDiscoverySessionCallbacks mCallbacks;
-
- public StubbablePrinterDiscoverySession(PrintService service,
- PrinterDiscoverySessionCallbacks callbacks) {
- mService = service;
- mCallbacks = callbacks;
- if (mCallbacks != null) {
- mCallbacks.setSession(this);
- }
- }
-
- public PrintService getService() {
- return mService;
- }
-
- @Override
- public void onStartPrinterDiscovery(@NonNull List<PrinterId> priorityList) {
- if (mCallbacks != null) {
- mCallbacks.onStartPrinterDiscovery(priorityList);
- }
- }
-
- @Override
- public void onStopPrinterDiscovery() {
- if (mCallbacks != null) {
- mCallbacks.onStopPrinterDiscovery();
- }
- }
-
- @Override
- public void onValidatePrinters(@NonNull List<PrinterId> printerIds) {
- if (mCallbacks != null) {
- mCallbacks.onValidatePrinters(printerIds);
- }
- }
-
- @Override
- public void onStartPrinterStateTracking(@NonNull PrinterId printerId) {
- if (mCallbacks != null) {
- mCallbacks.onStartPrinterStateTracking(printerId);
- }
- }
-
- @Override
- public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
- @NonNull CancellationSignal cancellationSignal,
- @NonNull CustomPrinterIconCallback callback) {
- if (mCallbacks != null) {
- mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback);
- }
- }
-
- @Override
- public void onStopPrinterStateTracking(@NonNull PrinterId printerId) {
- if (mCallbacks != null) {
- mCallbacks.onStopPrinterStateTracking(printerId);
- }
- }
-
- @Override
- public void onDestroy() {
- if (mCallbacks != null) {
- mCallbacks.onDestroy();
- }
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 461d537e86f9..4e8322183a8b 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -214,7 +214,7 @@ public class BatteryStatsNoteTest extends TestCase{
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
}
- /** Test BatteryStatsImpl.noteScreenStateLocked. */
+ /** Test BatteryStatsImpl.noteScreenStateLocked sets timebases and screen states correctly. */
@SmallTest
public void testNoteScreenStateLocked() throws Exception {
final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
@@ -233,4 +233,52 @@ public class BatteryStatsNoteTest extends TestCase{
assertEquals(bi.getScreenState(), Display.STATE_OFF);
}
+ /** Test BatteryStatsImpl.noteScreenStateLocked updates timers correctly.
+ *
+ * Unknown and doze should both be subset of off state
+ *
+ * Timeline 0----100----200----310----400------------1000
+ * Unknown -------
+ * On -------
+ * Off ------- ----------------------
+ * Doze ----------------
+ */
+ @SmallTest
+ public void testNoteScreenStateTimersLocked() throws Exception {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+ clocks.realtime = clocks.uptime = 100;
+ // Device startup, setOnBatteryLocked calls updateTimebases
+ bi.updateTimeBasesLocked(true, Display.STATE_UNKNOWN, 100_000, 100_000);
+ // Turn on display at 200us
+ clocks.realtime = clocks.uptime = 200;
+ bi.noteScreenStateLocked(Display.STATE_ON);
+ assertEquals(150_000, bi.computeBatteryRealtime(250_000, STATS_SINCE_CHARGED));
+ assertEquals(100_000, bi.computeBatteryScreenOffRealtime(250_000, STATS_SINCE_CHARGED));
+ assertEquals(50_000, bi.getScreenOnTime(250_000, STATS_SINCE_CHARGED));
+ assertEquals(0, bi.getScreenDozeTime(250_000, STATS_SINCE_CHARGED));
+
+ clocks.realtime = clocks.uptime = 310;
+ bi.noteScreenStateLocked(Display.STATE_OFF);
+ assertEquals(250_000, bi.computeBatteryRealtime(350_000, STATS_SINCE_CHARGED));
+ assertEquals(140_000, bi.computeBatteryScreenOffRealtime(350_000, STATS_SINCE_CHARGED));
+ assertEquals(110_000, bi.getScreenOnTime(350_000, STATS_SINCE_CHARGED));
+ assertEquals(0, bi.getScreenDozeTime(350_000, STATS_SINCE_CHARGED));
+
+ clocks.realtime = clocks.uptime = 400;
+ bi.noteScreenStateLocked(Display.STATE_DOZE);
+ assertEquals(400_000, bi.computeBatteryRealtime(500_000, STATS_SINCE_CHARGED));
+ assertEquals(290_000, bi.computeBatteryScreenOffRealtime(500_000, STATS_SINCE_CHARGED));
+ assertEquals(110_000, bi.getScreenOnTime(500_000, STATS_SINCE_CHARGED));
+ assertEquals(100_000, bi.getScreenDozeTime(500_000, STATS_SINCE_CHARGED));
+
+ clocks.realtime = clocks.uptime = 1000;
+ bi.noteScreenStateLocked(Display.STATE_OFF);
+ assertEquals(1400_000, bi.computeBatteryRealtime(1500_000, STATS_SINCE_CHARGED));
+ assertEquals(1290_000, bi.computeBatteryScreenOffRealtime(1500_000, STATS_SINCE_CHARGED));
+ assertEquals(110_000, bi.getScreenOnTime(1500_000, STATS_SINCE_CHARGED));
+ assertEquals(600_000, bi.getScreenDozeTime(1500_000, STATS_SINCE_CHARGED));
+ }
+
}
diff --git a/media/java/android/media/tv/ITvInputHardware.aidl b/media/java/android/media/tv/ITvInputHardware.aidl
index 96223ba7bac1..94c1013a837e 100644
--- a/media/java/android/media/tv/ITvInputHardware.aidl
+++ b/media/java/android/media/tv/ITvInputHardware.aidl
@@ -40,12 +40,6 @@ interface ITvInputHardware {
void setStreamVolume(float volume);
/**
- * Dispatch key event to HDMI service. The events would be automatically converted to
- * HDMI CEC commands. If the hardware is not representing an HDMI port, this method will fail.
- */
- boolean dispatchKeyEventToHdmi(in KeyEvent event);
-
- /**
* Override default audio sink from audio policy. When override is on, it is
* TvInputService's responsibility to adjust to audio configuration change
* (for example, when the audio sink becomes unavailable or more desirable
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d7a9edefa3f2..fd1f2cf66b79 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -2590,12 +2590,9 @@ public final class TvInputManager {
}
}
+ /** @removed */
public boolean dispatchKeyEventToHdmi(KeyEvent event) {
- try {
- return mInterface.dispatchKeyEventToHdmi(event);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ return false;
}
public void overrideAudioSink(int audioType, String audioAddress, int samplingRate,
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 7f6980de576a..28827e64cf96 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -24,7 +24,7 @@
#include <media/IMediaHTTPService.h>
#include <media/MediaPlayerInterface.h>
#include <media/MediaAnalyticsItem.h>
-#include <media/stagefright/Utils.h> // for FOURCC definition
+#include <media/stagefright/foundation/ByteUtils.h> // for FOURCC definition
#include <stdio.h>
#include <assert.h>
#include <limits.h>
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk
index 3c02453c78a1..149be743dbbb 100644
--- a/packages/PrintSpooler/tests/outofprocess/Android.mk
+++ b/packages/PrintSpooler/tests/outofprocess/Android.mk
@@ -21,7 +21,7 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 print-test-util-lib
LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml b/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml
index 4a05f6f52a9a..307cc936a567 100644
--- a/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml
+++ b/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml
@@ -21,10 +21,12 @@
<application>
<uses-library android:name="android.test.runner" />
- <activity android:name=".PrintTestActivity"/>
+ <activity
+ android:name="android.print.test.PrintDocumentActivity"
+ android:theme="@style/NoAnimation" />
<service
- android:name=".mockservice.MockPrintService"
+ android:name="android.print.test.services.FirstPrintService"
android:permission="android.permission.BIND_PRINT_SERVICE">
<intent-filter>
@@ -37,13 +39,15 @@
</service>
<activity
- android:name=".mockservice.SettingsActivity"
+ android:name="android.print.test.services.SettingsActivity"
android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+ android:theme="@style/NoAnimation"
android:exported="true">
</activity>
<activity
- android:name=".mockservice.AddPrintersActivity"
+ android:name="android.print.test.services.AddPrintersActivity"
+ android:theme="@style/NoAnimation"
android:exported="true">
</activity>
diff --git a/packages/PrintSpooler/tests/outofprocess/res/values/themes.xml b/packages/PrintSpooler/tests/outofprocess/res/values/themes.xml
new file mode 100644
index 000000000000..49eb2574da02
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/res/values/themes.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ 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.
+ -->
+<resources>
+ <style name="NoAnimation" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:windowAnimationStyle">@null</item>
+ </style>
+</resources>
diff --git a/packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml b/packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml
index 9eecf4562bb4..a6282b1c5bb4 100644
--- a/packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml
+++ b/packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml
@@ -17,4 +17,4 @@
-->
<print-service xmlns:android="http://schemas.android.com/apk/res/android"
- android:addPrintersActivity="com.android.printspooler.outofprocess.tests.mockservice.AddPrintersActivity" />
+ android:addPrintersActivity="android.print.test.services.AddPrintersActivity" />
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/BasePrintTest.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/BasePrintTest.java
deleted file mode 100644
index 9a7f362decb2..000000000000
--- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/BasePrintTest.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2016 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.printspooler.outofprocess.tests;
-
-import static android.content.pm.PackageManager.GET_META_DATA;
-import static android.content.pm.PackageManager.GET_SERVICES;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.app.Instrumentation;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.CancellationSignal;
-import android.os.ParcelFileDescriptor;
-import android.print.PrintAttributes;
-import android.print.PrintDocumentAdapter;
-import android.print.PrintManager;
-import android.print.PrinterId;
-import android.printservice.CustomPrinterIconCallback;
-import android.printservice.PrintJob;
-import android.printservice.PrintService;
-import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.uiautomator.UiDevice;
-
-import com.android.printspooler.outofprocess.tests.mockservice.PrintServiceCallbacks;
-import com.android.printspooler.outofprocess.tests.mockservice.PrinterDiscoverySessionCallbacks;
-import com.android.printspooler.outofprocess.tests.mockservice.StubbablePrinterDiscoverySession;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.mockito.stubbing.Answer;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.List;
-
-/**
- * This is the base class for print tests.
- */
-abstract class BasePrintTest {
- protected static final long OPERATION_TIMEOUT = 30000;
- private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success";
- private static final int CURRENT_USER_ID = -2; // Mirrors UserHandle.USER_CURRENT
- private static String sDisabledPrintServicesBefore;
-
- private android.print.PrintJob mPrintJob;
-
- private static Instrumentation sInstrumentation;
- private static UiDevice sUiDevice;
-
- @Rule
- public ActivityTestRule<PrintTestActivity> mActivityRule =
- new ActivityTestRule<>(PrintTestActivity.class, false, true);
-
- /**
- * Return the UI device
- *
- * @return the UI device
- */
- public UiDevice getUiDevice() {
- return sUiDevice;
- }
-
- protected static Instrumentation getInstrumentation() {
- return sInstrumentation;
- }
-
- @BeforeClass
- public static void setUpClass() throws Exception {
- sInstrumentation = InstrumentationRegistry.getInstrumentation();
- assumeTrue(sInstrumentation.getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_PRINTING));
-
- sUiDevice = UiDevice.getInstance(sInstrumentation);
-
- // Make sure we start with a clean slate.
- clearPrintSpoolerData();
-
- disablePrintServices(sInstrumentation.getTargetContext().getPackageName());
-
- // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
- // Dexmaker is used by mockito.
- System.setProperty("dexmaker.dexcache", getInstrumentation()
- .getTargetContext().getCacheDir().getPath());
- }
-
- @AfterClass
- public static void tearDownClass() throws Exception {
- enablePrintServices();
- }
-
- @Before
- public void unlockScreen() throws Exception {
- // Unlock screen.
- runShellCommand("input keyevent KEYCODE_WAKEUP");
- runShellCommand("wm dismiss-keyguard");
- }
-
- @After
- public void exitActivities() throws Exception {
- // Exit print spooler
- getUiDevice().pressBack();
- getUiDevice().pressBack();
- }
-
- protected android.print.PrintJob print(@NonNull final PrintDocumentAdapter adapter,
- final PrintAttributes attributes) {
- // Initiate printing as if coming from the app.
- getInstrumentation().runOnMainSync(() -> {
- PrintManager printManager = (PrintManager) getActivity()
- .getSystemService(Context.PRINT_SERVICE);
- mPrintJob = printManager.print("Print job", adapter, attributes);
- });
-
- return mPrintJob;
- }
-
- protected PrintTestActivity getActivity() {
- return mActivityRule.getActivity();
- }
-
- public static String runShellCommand(String cmd)
- throws IOException {
- ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(cmd);
- byte[] buf = new byte[512];
- int bytesRead;
- FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
- StringBuilder stdout = new StringBuilder();
- while ((bytesRead = fis.read(buf)) != -1) {
- stdout.append(new String(buf, 0, bytesRead));
- }
- fis.close();
- return stdout.toString();
- }
-
- protected static void clearPrintSpoolerData() throws Exception {
- assertTrue("failed to clear print spooler data", runShellCommand(
- String.format("pm clear --user %d %s", CURRENT_USER_ID,
- PrintManager.PRINT_SPOOLER_PACKAGE_NAME)).contains(
- PM_CLEAR_SUCCESS_OUTPUT));
- }
-
- /**
- * Disable all print services beside the ones we want to leave enabled.
- *
- * @param packageToLeaveEnabled The package of the services to leave enabled.
- */
- private static void disablePrintServices(String packageToLeaveEnabled) throws IOException {
- Instrumentation instrumentation = getInstrumentation();
-
- sDisabledPrintServicesBefore = runShellCommand(
- "settings get secure " + Settings.Secure.DISABLED_PRINT_SERVICES);
-
- Intent printServiceIntent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
- List<ResolveInfo> installedServices = instrumentation.getContext().getPackageManager()
- .queryIntentServices(printServiceIntent, GET_SERVICES | GET_META_DATA);
-
- StringBuilder builder = new StringBuilder();
- for (ResolveInfo service : installedServices) {
- if (packageToLeaveEnabled.equals(service.serviceInfo.packageName)) {
- continue;
- }
- if (builder.length() > 0) {
- builder.append(":");
- }
- builder.append(new ComponentName(service.serviceInfo.packageName,
- service.serviceInfo.name).flattenToString());
- }
-
- runShellCommand(
- "settings put secure " + Settings.Secure.DISABLED_PRINT_SERVICES + " " + builder);
- }
-
- /**
- * Revert {@link #disablePrintServices(String)}
- */
- private static void enablePrintServices() throws IOException {
- runShellCommand("settings put secure " + Settings.Secure.DISABLED_PRINT_SERVICES + " "
- + sDisabledPrintServicesBefore);
- }
-
- @SuppressWarnings("unchecked")
- protected PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
- Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery,
- Answer<Void> onValidatePrinters, Answer<Void> onStartPrinterStateTracking,
- Answer<Void> onRequestCustomPrinterIcon, Answer<Void> onStopPrinterStateTracking,
- Answer<Void> onDestroy) {
- PrinterDiscoverySessionCallbacks callbacks = mock(PrinterDiscoverySessionCallbacks.class);
-
- doCallRealMethod().when(callbacks).setSession(any(StubbablePrinterDiscoverySession.class));
- when(callbacks.getSession()).thenCallRealMethod();
-
- if (onStartPrinterDiscovery != null) {
- doAnswer(onStartPrinterDiscovery).when(callbacks).onStartPrinterDiscovery(
- any(List.class));
- }
- if (onStopPrinterDiscovery != null) {
- doAnswer(onStopPrinterDiscovery).when(callbacks).onStopPrinterDiscovery();
- }
- if (onValidatePrinters != null) {
- doAnswer(onValidatePrinters).when(callbacks).onValidatePrinters(
- any(List.class));
- }
- if (onStartPrinterStateTracking != null) {
- doAnswer(onStartPrinterStateTracking).when(callbacks).onStartPrinterStateTracking(
- any(PrinterId.class));
- }
- if (onRequestCustomPrinterIcon != null) {
- doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
- any(PrinterId.class), any(CancellationSignal.class),
- any(CustomPrinterIconCallback.class));
- }
- if (onStopPrinterStateTracking != null) {
- doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
- any(PrinterId.class));
- }
- if (onDestroy != null) {
- doAnswer(onDestroy).when(callbacks).onDestroy();
- }
-
- return callbacks;
- }
-
- protected PrintServiceCallbacks createMockPrintServiceCallbacks(
- Answer<PrinterDiscoverySessionCallbacks> onCreatePrinterDiscoverySessionCallbacks,
- Answer<Void> onPrintJobQueued, Answer<Void> onRequestCancelPrintJob) {
- final PrintServiceCallbacks service = mock(PrintServiceCallbacks.class);
-
- doCallRealMethod().when(service).setService(any(PrintService.class));
- when(service.getService()).thenCallRealMethod();
-
- if (onCreatePrinterDiscoverySessionCallbacks != null) {
- doAnswer(onCreatePrinterDiscoverySessionCallbacks).when(service)
- .onCreatePrinterDiscoverySessionCallbacks();
- }
- if (onPrintJobQueued != null) {
- doAnswer(onPrintJobQueued).when(service).onPrintJobQueued(any(PrintJob.class));
- }
- if (onRequestCancelPrintJob != null) {
- doAnswer(onRequestCancelPrintJob).when(service).onRequestCancelPrintJob(
- any(PrintJob.class));
- }
-
- return service;
- }
-}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/PrintTestActivity.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/PrintTestActivity.java
deleted file mode 100644
index 4905a0b5b5fa..000000000000
--- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/PrintTestActivity.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2016 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.printspooler.outofprocess.tests;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.WindowManager;
-
-public class PrintTestActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
- }
-}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java
index 78a0cac623ba..7ebf93d8f4ed 100644
--- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java
@@ -30,6 +30,11 @@ import android.print.PrinterCapabilitiesInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.print.pdf.PrintedPdfDocument;
+import android.print.test.BasePrintTest;
+import android.print.test.services.AddPrintersActivity;
+import android.print.test.services.FirstPrintService;
+import android.print.test.services.PrinterDiscoverySessionCallbacks;
+import android.print.test.services.StubbablePrinterDiscoverySession;
import android.support.test.filters.LargeTest;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject;
@@ -38,11 +43,6 @@ import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.util.Log;
-import com.android.printspooler.outofprocess.tests.mockservice.AddPrintersActivity;
-import com.android.printspooler.outofprocess.tests.mockservice.MockPrintService;
-import com.android.printspooler.outofprocess.tests.mockservice.PrinterDiscoverySessionCallbacks;
-import com.android.printspooler.outofprocess.tests.mockservice.StubbablePrinterDiscoverySession;
-
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -62,10 +62,6 @@ import java.util.function.Supplier;
public class WorkflowTest extends BasePrintTest {
private static final String LOG_TAG = WorkflowTest.class.getSimpleName();
- private static float sWindowAnimationScaleBefore;
- private static float sTransitionAnimationScaleBefore;
- private static float sAnimatiorDurationScaleBefore;
-
private PrintAttributes.MediaSize mFirst;
private boolean mSelectPrinter;
private PrintAttributes.MediaSize mSecond;
@@ -91,7 +87,7 @@ public class WorkflowTest extends BasePrintTest {
throws TimeoutException, InterruptedException {
long startTime = System.currentTimeMillis();
while (condition.get()) {
- long timeLeft = OPERATION_TIMEOUT - (System.currentTimeMillis() - startTime);
+ long timeLeft = OPERATION_TIMEOUT_MILLIS - (System.currentTimeMillis() - startTime);
if (timeLeft < 0) {
throw new TimeoutException();
}
@@ -156,7 +152,7 @@ public class WorkflowTest extends BasePrintTest {
*/
private void setMockPrintServiceCallbacks(StubbablePrinterDiscoverySession[] sessionRef,
ArrayList<String> trackedPrinters, PrintAttributes.MediaSize mediaSize) {
- MockPrintService.setCallbacks(createMockPrintServiceCallbacks(
+ FirstPrintService.setCallbacks(createMockPrintServiceCallbacks(
inv -> createMockPrinterDiscoverySessionCallbacks(inv2 -> {
synchronized (sessionRef) {
sessionRef[0] = ((PrinterDiscoverySessionCallbacks) inv2.getMock())
@@ -243,7 +239,7 @@ public class WorkflowTest extends BasePrintTest {
callback.onWriteFailed(e.getMessage());
}
}
- }, null);
+ }, (PrintAttributes) null);
}
@Parameterized.Parameters
@@ -303,7 +299,7 @@ public class WorkflowTest extends BasePrintTest {
} else {
Log.i(LOG_TAG, "Waiting for error message");
assertNotNull(getUiDevice().wait(Until.findObject(
- By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+ By.text("This printer isn't available right now.")), OPERATION_TIMEOUT_MILLIS));
}
setPrinter("All printers\u2026");
@@ -316,7 +312,7 @@ public class WorkflowTest extends BasePrintTest {
() -> addPrinter(session[0], "2nd printer", mSecond));
// This executes the observer registered above
- clickOn(new UiSelector().text(MockPrintService.class.getCanonicalName())
+ clickOn(new UiSelector().text(FirstPrintService.class.getCanonicalName())
.resourceId("com.android.printspooler:id/title"));
getUiDevice().pressBack();
@@ -342,7 +338,8 @@ public class WorkflowTest extends BasePrintTest {
} else {
Log.i(LOG_TAG, "Waiting for error message");
assertNotNull(getUiDevice().wait(Until.findObject(
- By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+ By.text("This printer isn't available right now.")),
+ OPERATION_TIMEOUT_MILLIS));
}
Log.i(LOG_TAG, "Waiting for 1st printer to be not tracked");
@@ -370,7 +367,8 @@ public class WorkflowTest extends BasePrintTest {
} else {
Log.i(LOG_TAG, "Waiting for error message");
assertNotNull(getUiDevice().wait(Until.findObject(
- By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+ By.text("This printer isn't available right now.")),
+ OPERATION_TIMEOUT_MILLIS));
}
Log.i(LOG_TAG, "Waiting for 1st printer to be tracked");
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/AddPrintersActivity.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/AddPrintersActivity.java
deleted file mode 100644
index 2ea4e7dcdbe2..000000000000
--- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/AddPrintersActivity.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 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.printspooler.outofprocess.tests.mockservice;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-
-import java.util.ArrayList;
-
-public class AddPrintersActivity extends Activity {
- private static final ArrayList<Runnable> sObservers = new ArrayList<>();
-
- public static void addObserver(@NonNull Runnable observer) {
- synchronized (sObservers) {
- sObservers.add(observer);
- }
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- synchronized (sObservers) {
- for (Runnable sObserver : sObservers) {
- sObserver.run();
- }
- }
-
- finish();
- }
-
- public static void clearObservers() {
- synchronized (sObservers) {
- sObservers.clear();
- }
- }
-}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/MockPrintService.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/MockPrintService.java
deleted file mode 100644
index 3a231130c5c4..000000000000
--- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/MockPrintService.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 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.printspooler.outofprocess.tests.mockservice;
-
-public class MockPrintService extends StubbablePrintService {
-
- private static final Object sLock = new Object();
-
- private static PrintServiceCallbacks sCallbacks;
-
- public static void setCallbacks(PrintServiceCallbacks callbacks) {
- synchronized (sLock) {
- sCallbacks = callbacks;
- }
- }
-
- @Override
- protected PrintServiceCallbacks getCallbacks() {
- synchronized (sLock) {
- if (sCallbacks != null) {
- sCallbacks.setService(this);
- }
- return sCallbacks;
- }
- }
-}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrintServiceCallbacks.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrintServiceCallbacks.java
deleted file mode 100644
index 07baa0fe1191..000000000000
--- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrintServiceCallbacks.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 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.printspooler.outofprocess.tests.mockservice;
-
-import android.printservice.PrintJob;
-import android.printservice.PrintService;
-
-public abstract class PrintServiceCallbacks {
-
- private PrintService mService;
-
- public PrintService getService() {
- return mService;
- }
-
- public void setService(PrintService service) {
- mService = service;
- }
-
- public abstract PrinterDiscoverySessionCallbacks onCreatePrinterDiscoverySessionCallbacks();
-
- public abstract void onRequestCancelPrintJob(PrintJob printJob);
-
- public abstract void onPrintJobQueued(PrintJob printJob);
-}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrinterDiscoverySessionCallbacks.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrinterDiscoverySessionCallbacks.java
deleted file mode 100644
index 5c1260c37dc4..000000000000
--- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrinterDiscoverySessionCallbacks.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2016 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.printspooler.outofprocess.tests.mockservice;
-
-import android.os.CancellationSignal;
-import android.print.PrinterId;
-import android.printservice.CustomPrinterIconCallback;
-
-import java.util.List;
-
-public abstract class PrinterDiscoverySessionCallbacks {
-
- private StubbablePrinterDiscoverySession mSession;
-
- public void setSession(StubbablePrinterDiscoverySession session) {
- mSession = session;
- }
-
- public StubbablePrinterDiscoverySession getSession() {
- return mSession;
- }
-
- public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
-
- public abstract void onStopPrinterDiscovery();
-
- public abstract void onValidatePrinters(List<PrinterId> printerIds);
-
- public abstract void onStartPrinterStateTracking(PrinterId printerId);
-
- public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
- CancellationSignal cancellationSignal, CustomPrinterIconCallback callback);
-
- public abstract void onStopPrinterStateTracking(PrinterId printerId);
-
- public abstract void onDestroy();
-}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrintService.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrintService.java
deleted file mode 100644
index be9d19b4d634..000000000000
--- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrintService.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 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.printspooler.outofprocess.tests.mockservice;
-
-import android.printservice.PrintJob;
-import android.printservice.PrintService;
-import android.printservice.PrinterDiscoverySession;
-
-public abstract class StubbablePrintService extends PrintService {
-
- @Override
- public PrinterDiscoverySession onCreatePrinterDiscoverySession() {
- PrintServiceCallbacks callbacks = getCallbacks();
- if (callbacks != null) {
- return new StubbablePrinterDiscoverySession(this,
- getCallbacks().onCreatePrinterDiscoverySessionCallbacks());
- }
- return null;
- }
-
- @Override
- public void onRequestCancelPrintJob(PrintJob printJob) {
- PrintServiceCallbacks callbacks = getCallbacks();
- if (callbacks != null) {
- callbacks.onRequestCancelPrintJob(printJob);
- }
- }
-
- @Override
- public void onPrintJobQueued(PrintJob printJob) {
- PrintServiceCallbacks callbacks = getCallbacks();
- if (callbacks != null) {
- callbacks.onPrintJobQueued(printJob);
- }
- }
-
- protected abstract PrintServiceCallbacks getCallbacks();
-}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrinterDiscoverySession.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrinterDiscoverySession.java
deleted file mode 100644
index a828cd6b39db..000000000000
--- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrinterDiscoverySession.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2016 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.printspooler.outofprocess.tests.mockservice;
-
-import android.os.CancellationSignal;
-import android.print.PrinterId;
-import android.printservice.CustomPrinterIconCallback;
-import android.printservice.PrintService;
-import android.printservice.PrinterDiscoverySession;
-import android.support.annotation.NonNull;
-
-import java.util.List;
-
-public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession {
- private final PrintService mService;
- private final PrinterDiscoverySessionCallbacks mCallbacks;
-
- public StubbablePrinterDiscoverySession(PrintService service,
- PrinterDiscoverySessionCallbacks callbacks) {
- mService = service;
- mCallbacks = callbacks;
- if (mCallbacks != null) {
- mCallbacks.setSession(this);
- }
- }
-
- public PrintService getService() {
- return mService;
- }
-
- @Override
- public void onStartPrinterDiscovery(@NonNull List<PrinterId> priorityList) {
- if (mCallbacks != null) {
- mCallbacks.onStartPrinterDiscovery(priorityList);
- }
- }
-
- @Override
- public void onStopPrinterDiscovery() {
- if (mCallbacks != null) {
- mCallbacks.onStopPrinterDiscovery();
- }
- }
-
- @Override
- public void onValidatePrinters(@NonNull List<PrinterId> printerIds) {
- if (mCallbacks != null) {
- mCallbacks.onValidatePrinters(printerIds);
- }
- }
-
- @Override
- public void onStartPrinterStateTracking(@NonNull PrinterId printerId) {
- if (mCallbacks != null) {
- mCallbacks.onStartPrinterStateTracking(printerId);
- }
- }
-
- @Override
- public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
- @NonNull CancellationSignal cancellationSignal,
- @NonNull CustomPrinterIconCallback callback) {
- if (mCallbacks != null) {
- mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback);
- }
- }
-
- @Override
- public void onStopPrinterStateTracking(@NonNull PrinterId printerId) {
- if (mCallbacks != null) {
- mCallbacks.onStopPrinterStateTracking(printerId);
- }
- }
-
- @Override
- public void onDestroy() {
- if (mCallbacks != null) {
- mCallbacks.onDestroy();
- }
- }
-}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index b72869518c45..3d083b124df2 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -983,4 +983,14 @@
<!-- [CHAR LIMIT=NONE] Dialog body explaining that the app just selected by the user will not work after a reboot until until after the user enters their credentials, such as a PIN or password. -->
<string name="direct_boot_unaware_dialog_message">Note: After a reboot, this app can\'t start until you unlock your phone</string>
+ <!--Label of IMS registration header -->
+ <string name="ims_reg_title">"IMS registration state"</string>
+ <!--Used when IMS registration state is registered -->
+ <string name="ims_reg_status_registered">"Registered"</string>
+ <!--Used when IMS registration state is not registered -->
+ <string name="ims_reg_status_not_registered">"Not registered"</string>
+
+ <!-- About phone, status item value if the actual value is not available. -->
+ <string name="status_unavailable">Unavailable</string>
+
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogdSizePreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogdSizePreferenceController.java
index 7998b2ef872b..f79be7eaddb1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogdSizePreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogdSizePreferenceController.java
@@ -33,21 +33,27 @@ public abstract class AbstractLogdSizePreferenceController extends
+ "AbstractLogdSizePreferenceController.LOGD_SIZE_UPDATED";
public static final String EXTRA_CURRENT_LOGD_VALUE = "CURRENT_LOGD_VALUE";
+ @VisibleForTesting
+ static final String LOW_RAM_CONFIG_PROPERTY_KEY = "ro.config.low_ram";
private static final String SELECT_LOGD_SIZE_KEY = "select_logd_size";
@VisibleForTesting
static final String SELECT_LOGD_SIZE_PROPERTY = "persist.logd.size";
static final String SELECT_LOGD_TAG_PROPERTY = "persist.log.tag";
// Tricky, isLoggable only checks for first character, assumes silence
static final String SELECT_LOGD_TAG_SILENCE = "Settings";
- private static final String SELECT_LOGD_SNET_TAG_PROPERTY = "persist.log.tag.snet_event_log";
+ @VisibleForTesting
+ static final String SELECT_LOGD_SNET_TAG_PROPERTY = "persist.log.tag.snet_event_log";
private static final String SELECT_LOGD_RUNTIME_SNET_TAG_PROPERTY = "log.tag.snet_event_log";
private static final String SELECT_LOGD_DEFAULT_SIZE_PROPERTY = "ro.logd.size";
@VisibleForTesting
static final String SELECT_LOGD_DEFAULT_SIZE_VALUE = "262144";
private static final String SELECT_LOGD_SVELTE_DEFAULT_SIZE_VALUE = "65536";
// 32768 is merely a menu marker, 64K is our lowest log buffer size we replace it with.
- private static final String SELECT_LOGD_MINIMUM_SIZE_VALUE = "65536";
+ @VisibleForTesting
+ static final String SELECT_LOGD_MINIMUM_SIZE_VALUE = "65536";
static final String SELECT_LOGD_OFF_SIZE_MARKER_VALUE = "32768";
+ @VisibleForTesting
+ static final String DEFAULT_SNET_TAG = "I";
private ListPreference mLogdSize;
@@ -154,7 +160,7 @@ public abstract class AbstractLogdSizePreferenceController extends
if ((snetValue == null) || (snetValue.length() == 0)) {
snetValue = SystemProperties.get(SELECT_LOGD_RUNTIME_SNET_TAG_PROPERTY);
if ((snetValue == null) || (snetValue.length() == 0)) {
- SystemProperties.set(SELECT_LOGD_SNET_TAG_PROPERTY, "I");
+ SystemProperties.set(SELECT_LOGD_SNET_TAG_PROPERTY, DEFAULT_SNET_TAG);
}
}
// Silence all log sources, security logs notwithstanding
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java
new file mode 100644
index 000000000000..ba358f83c9d5
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java
@@ -0,0 +1,85 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+
+import com.android.settingslib.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+/**
+ * Preference controller for bluetooth address
+ */
+public abstract class AbstractBluetoothAddressPreferenceController
+ extends AbstractConnectivityPreferenceController {
+
+ @VisibleForTesting
+ static final String KEY_BT_ADDRESS = "bt_address";
+
+ private static final String[] CONNECTIVITY_INTENTS = {
+ BluetoothAdapter.ACTION_STATE_CHANGED
+ };
+
+ private Preference mBtAddress;
+
+ public AbstractBluetoothAddressPreferenceController(Context context, Lifecycle lifecycle) {
+ super(context, lifecycle);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return BluetoothAdapter.getDefaultAdapter() != null;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_BT_ADDRESS;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mBtAddress = screen.findPreference(KEY_BT_ADDRESS);
+ updateConnectivity();
+ }
+
+ @Override
+ protected String[] getConnectivityIntents() {
+ return CONNECTIVITY_INTENTS;
+ }
+
+ @SuppressLint("HardwareIds")
+ @Override
+ protected void updateConnectivity() {
+ BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
+ if (bluetooth != null && mBtAddress != null) {
+ String address = bluetooth.isEnabled() ? bluetooth.getAddress() : null;
+ if (!TextUtils.isEmpty(address)) {
+ // Convert the address to lowercase for consistency with the wifi MAC address.
+ mBtAddress.setSummary(address.toLowerCase());
+ } else {
+ mBtAddress.setSummary(R.string.status_unavailable);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractConnectivityPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractConnectivityPreferenceController.java
new file mode 100644
index 000000000000..c6552f77a2b2
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractConnectivityPreferenceController.java
@@ -0,0 +1,114 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.Message;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Base class for preference controllers which listen to connectivity broadcasts
+ */
+public abstract class AbstractConnectivityPreferenceController
+ extends AbstractPreferenceController implements LifecycleObserver, OnStart, OnStop {
+
+ private final BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (ArrayUtils.contains(getConnectivityIntents(), action)) {
+ getHandler().sendEmptyMessage(EVENT_UPDATE_CONNECTIVITY);
+ }
+ }
+ };
+
+ private static final int EVENT_UPDATE_CONNECTIVITY = 600;
+
+ private Handler mHandler;
+
+ public AbstractConnectivityPreferenceController(Context context, Lifecycle lifecycle) {
+ super(context);
+ if (lifecycle != null) {
+ lifecycle.addObserver(this);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ mContext.unregisterReceiver(mConnectivityReceiver);
+ }
+
+ @Override
+ public void onStart() {
+ final IntentFilter connectivityIntentFilter = new IntentFilter();
+ final String[] intents = getConnectivityIntents();
+ for (String intent : intents) {
+ connectivityIntentFilter.addAction(intent);
+ }
+
+ mContext.registerReceiver(mConnectivityReceiver, connectivityIntentFilter,
+ android.Manifest.permission.CHANGE_NETWORK_STATE, null);
+ }
+
+ protected abstract String[] getConnectivityIntents();
+
+ protected abstract void updateConnectivity();
+
+ private Handler getHandler() {
+ if (mHandler == null) {
+ mHandler = new ConnectivityEventHandler(this);
+ }
+ return mHandler;
+ }
+
+ private static class ConnectivityEventHandler extends Handler {
+ private WeakReference<AbstractConnectivityPreferenceController> mPreferenceController;
+
+ public ConnectivityEventHandler(AbstractConnectivityPreferenceController activity) {
+ mPreferenceController = new WeakReference<>(activity);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ AbstractConnectivityPreferenceController preferenceController
+ = mPreferenceController.get();
+ if (preferenceController == null) {
+ return;
+ }
+
+ switch (msg.what) {
+ case EVENT_UPDATE_CONNECTIVITY:
+ preferenceController.updateConnectivity();
+ break;
+ default:
+ throw new IllegalStateException("Unknown message " + msg.what);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractImsStatusPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractImsStatusPreferenceController.java
new file mode 100644
index 000000000000..bb8404b0abd5
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractImsStatusPreferenceController.java
@@ -0,0 +1,95 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.os.PersistableBundle;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import com.android.settingslib.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+/**
+ * Preference controller for IMS status
+ */
+public abstract class AbstractImsStatusPreferenceController
+ extends AbstractConnectivityPreferenceController {
+
+ @VisibleForTesting
+ static final String KEY_IMS_REGISTRATION_STATE = "ims_reg_state";
+
+ private static final String[] CONNECTIVITY_INTENTS = {
+ BluetoothAdapter.ACTION_STATE_CHANGED,
+ ConnectivityManager.CONNECTIVITY_ACTION,
+ WifiManager.LINK_CONFIGURATION_CHANGED_ACTION,
+ WifiManager.NETWORK_STATE_CHANGED_ACTION,
+ };
+
+ private Preference mImsStatus;
+
+ public AbstractImsStatusPreferenceController(Context context,
+ Lifecycle lifecycle) {
+ super(context, lifecycle);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class);
+ int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+ PersistableBundle config = null;
+ if (configManager != null) {
+ config = configManager.getConfigForSubId(subId);
+ }
+ return config != null && config.getBoolean(
+ CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_IMS_REGISTRATION_STATE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mImsStatus = screen.findPreference(KEY_IMS_REGISTRATION_STATE);
+ updateConnectivity();
+ }
+
+ @Override
+ protected String[] getConnectivityIntents() {
+ return CONNECTIVITY_INTENTS;
+ }
+
+ @Override
+ protected void updateConnectivity() {
+ int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+ if (mImsStatus != null) {
+ TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ mImsStatus.setSummary((tm != null && tm.isImsRegistered(subId)) ?
+ R.string.ims_reg_status_registered : R.string.ims_reg_status_not_registered);
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java
new file mode 100644
index 000000000000..ded30226e2ae
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java
@@ -0,0 +1,112 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.wifi.WifiManager;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settingslib.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import java.net.InetAddress;
+import java.util.Iterator;
+
+/**
+ * Preference controller for IP address
+ */
+public abstract class AbstractIpAddressPreferenceController
+ extends AbstractConnectivityPreferenceController {
+
+ @VisibleForTesting
+ static final String KEY_IP_ADDRESS = "wifi_ip_address";
+
+ private static final String[] CONNECTIVITY_INTENTS = {
+ ConnectivityManager.CONNECTIVITY_ACTION,
+ WifiManager.LINK_CONFIGURATION_CHANGED_ACTION,
+ WifiManager.NETWORK_STATE_CHANGED_ACTION,
+ };
+
+ private Preference mIpAddress;
+ private final ConnectivityManager mCM;
+
+ public AbstractIpAddressPreferenceController(Context context, Lifecycle lifecycle) {
+ super(context, lifecycle);
+ mCM = context.getSystemService(ConnectivityManager.class);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_IP_ADDRESS;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mIpAddress = screen.findPreference(KEY_IP_ADDRESS);
+ updateConnectivity();
+ }
+
+ @Override
+ protected String[] getConnectivityIntents() {
+ return CONNECTIVITY_INTENTS;
+ }
+
+ @Override
+ protected void updateConnectivity() {
+ String ipAddress = getDefaultIpAddresses(mCM);
+ if (ipAddress != null) {
+ mIpAddress.setSummary(ipAddress);
+ } else {
+ mIpAddress.setSummary(R.string.status_unavailable);
+ }
+ }
+
+ /**
+ * Returns the default link's IP addresses, if any, taking into account IPv4 and IPv6 style
+ * addresses.
+ * @param cm ConnectivityManager
+ * @return the formatted and newline-separated IP addresses, or null if none.
+ */
+ private static String getDefaultIpAddresses(ConnectivityManager cm) {
+ LinkProperties prop = cm.getActiveLinkProperties();
+ return formatIpAddresses(prop);
+ }
+
+ private static String formatIpAddresses(LinkProperties prop) {
+ if (prop == null) return null;
+ Iterator<InetAddress> iter = prop.getAllAddresses().iterator();
+ // If there are no entries, return null
+ if (!iter.hasNext()) return null;
+ // Concatenate all available addresses, newline separated
+ StringBuilder addresses = new StringBuilder();
+ while (iter.hasNext()) {
+ addresses.append(iter.next().getHostAddress());
+ if (iter.hasNext()) addresses.append("\n");
+ }
+ return addresses.toString();
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java
new file mode 100644
index 000000000000..ac61ade19222
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java
@@ -0,0 +1,119 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.format.DateUtils;
+
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Preference controller for uptime
+ */
+public abstract class AbstractUptimePreferenceController extends AbstractPreferenceController
+ implements LifecycleObserver, OnStart, OnStop {
+
+ @VisibleForTesting
+ static final String KEY_UPTIME = "up_time";
+ private static final int EVENT_UPDATE_STATS = 500;
+
+ private Preference mUptime;
+ private Handler mHandler;
+
+ public AbstractUptimePreferenceController(Context context, Lifecycle lifecycle) {
+ super(context);
+ if (lifecycle != null) {
+ lifecycle.addObserver(this);
+ }
+ }
+
+ @Override
+ public void onStart() {
+ getHandler().sendEmptyMessage(EVENT_UPDATE_STATS);
+ }
+
+ @Override
+ public void onStop() {
+ getHandler().removeMessages(EVENT_UPDATE_STATS);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_UPTIME;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mUptime = screen.findPreference(KEY_UPTIME);
+ updateTimes();
+ }
+
+ private Handler getHandler() {
+ if (mHandler == null) {
+ mHandler = new MyHandler(this);
+ }
+ return mHandler;
+ }
+
+ private void updateTimes() {
+ mUptime.setSummary(DateUtils.formatDuration(SystemClock.elapsedRealtime()));
+ }
+
+ private static class MyHandler extends Handler {
+ private WeakReference<AbstractUptimePreferenceController> mStatus;
+
+ public MyHandler(AbstractUptimePreferenceController activity) {
+ mStatus = new WeakReference<>(activity);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ AbstractUptimePreferenceController status = mStatus.get();
+ if (status == null) {
+ return;
+ }
+
+ switch (msg.what) {
+ case EVENT_UPDATE_STATS:
+ status.updateTimes();
+ sendEmptyMessageDelayed(EVENT_UPDATE_STATS, 1000);
+ break;
+
+ default:
+ throw new IllegalStateException("Unknown message " + msg.what);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java
new file mode 100644
index 000000000000..d57b64f0c0cb
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java
@@ -0,0 +1,88 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+
+import com.android.settingslib.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+/**
+ * Preference controller for WIFI MAC address
+ */
+public abstract class AbstractWifiMacAddressPreferenceController
+ extends AbstractConnectivityPreferenceController {
+
+ @VisibleForTesting
+ static final String KEY_WIFI_MAC_ADDRESS = "wifi_mac_address";
+
+ private static final String[] CONNECTIVITY_INTENTS = {
+ ConnectivityManager.CONNECTIVITY_ACTION,
+ WifiManager.LINK_CONFIGURATION_CHANGED_ACTION,
+ WifiManager.NETWORK_STATE_CHANGED_ACTION,
+ };
+
+ private Preference mWifiMacAddress;
+ private final WifiManager mWifiManager;
+
+ public AbstractWifiMacAddressPreferenceController(Context context, Lifecycle lifecycle) {
+ super(context, lifecycle);
+ mWifiManager = context.getSystemService(WifiManager.class);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_WIFI_MAC_ADDRESS;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mWifiMacAddress = screen.findPreference(KEY_WIFI_MAC_ADDRESS);
+ updateConnectivity();
+ }
+
+ @Override
+ protected String[] getConnectivityIntents() {
+ return CONNECTIVITY_INTENTS;
+ }
+
+ @SuppressLint("HardwareIds")
+ @Override
+ protected void updateConnectivity() {
+ WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+ String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
+ if (!TextUtils.isEmpty(macAddress)) {
+ mWifiMacAddress.setSummary(macAddress);
+ } else {
+ mWifiMacAddress.setSummary(R.string.status_unavailable);
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
index 56b84415e907..9c347631d817 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
@@ -261,7 +261,7 @@ public class SuggestionParser {
if (requiredAccountType == null) {
return true;
}
- AccountManager accountManager = AccountManager.get(mContext);
+ AccountManager accountManager = mContext.getSystemService(AccountManager.class);
Account[] accounts = accountManager.getAccountsByType(requiredAccountType);
boolean satisfiesRequiredAccount = accounts.length > 0;
if (!satisfiesRequiredAccount) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 12455d85588b..c56e1da14921 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -291,15 +291,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
}
/**
- * Force a scan for wifi networks to happen now.
- */
- public void forceScan() {
- if (mWifiManager.isWifiEnabled() && mScanner != null) {
- mScanner.forceScan();
- }
- }
-
- /**
* Temporarily stop scanning for wifi networks.
*/
public void pauseScanning() {
@@ -789,14 +780,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
}
}
- public static List<AccessPoint> getCurrentAccessPoints(Context context, boolean includeSaved,
- boolean includeScans) {
- WifiTracker tracker = new WifiTracker(context, null, includeSaved, includeScans);
- tracker.forceUpdate();
- tracker.copyAndNotifyListeners(false /*notifyListeners*/);
- return tracker.getAccessPoints();
- }
-
@VisibleForTesting
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -986,11 +969,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
}
}
- void forceScan() {
- removeMessages(MSG_SCAN);
- sendEmptyMessage(MSG_SCAN);
- }
-
void pause() {
mRetry = 0;
removeMessages(MSG_SCAN);
diff --git a/packages/SettingsLib/tests/robotests/Android.mk b/packages/SettingsLib/tests/robotests/Android.mk
index 55b635ec9b24..bc1a834535a6 100644
--- a/packages/SettingsLib/tests/robotests/Android.mk
+++ b/packages/SettingsLib/tests/robotests/Android.mk
@@ -42,11 +42,12 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
# Include the testing libraries (JUnit4 + Robolectric libs).
LOCAL_STATIC_JAVA_LIBRARIES := \
mockito-robolectric-prebuilt \
+ platform-robolectric-android-all-stubs \
truth-prebuilt
LOCAL_JAVA_LIBRARIES := \
junit \
- platform-robolectric-prebuilt
+ platform-robolectric-3.4.2-prebuilt
LOCAL_INSTRUMENTATION_FOR := SettingsLibShell
LOCAL_MODULE := SettingsLibRoboTests
@@ -69,4 +70,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
LOCAL_TEST_PACKAGE := SettingsLibShell
-include prebuilts/misc/common/robolectric/run_robotests.mk
+LOCAL_ROBOTEST_TIMEOUT := 36000
+
+include prebuilts/misc/common/robolectric/3.4.2/run_robotests.mk
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index c3a505ac67f4..ca366ea4b6cc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -20,8 +20,11 @@ import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NO
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -56,10 +59,10 @@ public class RestrictedLockUtilsTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private RestrictedLockUtils.Proxy mProxy;
- private static final int mUserId = 194;
- private static final int mProfileId = 160;
- private static final ComponentName mAdmin1 = new ComponentName("admin1", "admin1class");
- private static final ComponentName mAdmin2 = new ComponentName("admin2", "admin2class");
+ private final int mUserId = 194;
+ private final int mProfileId = 160;
+ private final ComponentName mAdmin1 = new ComponentName("admin1", "admin1class");
+ private final ComponentName mAdmin2 = new ComponentName("admin2", "admin2class");
@Before
public void setUp() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
index 8099eb11edb4..698e44247e73 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
@@ -53,15 +53,15 @@ public class SettingsLibRobolectricTestRunner extends RobolectricTestRunner {
static void getIncludedResourcePaths(String packageName, List<ResourcePath> paths) {
paths.add(new ResourcePath(
- packageName,
+ null,
Fs.fileFromPath("./frameworks/base/packages/SettingsLib/res"),
null));
paths.add(new ResourcePath(
- packageName,
+ null,
Fs.fileFromPath("./frameworks/base/core/res/res"),
null));
paths.add(new ResourcePath(
- packageName,
+ null,
Fs.fileFromPath("./frameworks/support/v7/appcompat/res"),
null));
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
index 31abecda9a39..3af976836439 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
@@ -17,7 +17,7 @@
package com.android.settingslib;
public class TestConfig {
- public static final int SDK_VERSION = 23;
+ public static final int SDK_VERSION = 25;
public static final String MANIFEST_PATH =
"frameworks/base/packages/SettingsLib/tests/robotests/AndroidManifest.xml";
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
index d6bca0e27b3b..1290391e3ce2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
@@ -35,9 +35,9 @@ import com.android.settingslib.core.lifecycle.events.OnStop;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.android.controller.FragmentController;
import org.robolectric.annotation.Config;
-import org.robolectric.util.ActivityController;
-import org.robolectric.util.FragmentController;
import static com.google.common.truth.Truth.assertThat;
@@ -168,7 +168,7 @@ public class LifecycleTest {
Robolectric.buildFragment(TestDialogFragment.class);
TestDialogFragment fragment = fragmentController.get();
- fragmentController.attach().create().start().resume();
+ fragmentController.create().start().resume();
fragment.onCreateOptionsMenu(null, null);
fragment.onPrepareOptionsMenu(null);
fragment.onOptionsItemSelected(null);
@@ -192,7 +192,7 @@ public class LifecycleTest {
Robolectric.buildFragment(TestFragment.class);
TestFragment fragment = fragmentController.get();
- fragmentController.attach().create().start().resume();
+ fragmentController.create().start().resume();
fragment.onCreateOptionsMenu(null, null);
fragment.onPrepareOptionsMenu(null);
fragment.onOptionsItemSelected(null);
@@ -235,7 +235,7 @@ public class LifecycleTest {
OptionItemAccepter accepter = new OptionItemAccepter();
fragment.getLifecycle().addObserver(accepter);
- fragmentController.attach().create().start().resume();
+ fragmentController.create().start().resume();
fragment.onCreateOptionsMenu(null, null);
fragment.onPrepareOptionsMenu(null);
fragment.onOptionsItemSelected(null);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java
index 94bfd8f22de2..26d357018a75 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java
@@ -16,9 +16,29 @@
package com.android.settingslib.development;
+import static com.android.settingslib.development.AbstractLogdSizePreferenceController
+ .DEFAULT_SNET_TAG;
+import static com.android.settingslib.development.AbstractLogdSizePreferenceController
+ .LOW_RAM_CONFIG_PROPERTY_KEY;
+import static com.android.settingslib.development.AbstractLogdSizePreferenceController
+ .SELECT_LOGD_MINIMUM_SIZE_VALUE;
+import static com.android.settingslib.development.AbstractLogdSizePreferenceController
+ .SELECT_LOGD_OFF_SIZE_MARKER_VALUE;
+import static com.android.settingslib.development.AbstractLogdSizePreferenceController
+ .SELECT_LOGD_SIZE_PROPERTY;
+import static com.android.settingslib.development.AbstractLogdSizePreferenceController
+ .SELECT_LOGD_SNET_TAG_PROPERTY;
+import static com.android.settingslib.development.AbstractLogdSizePreferenceController
+ .SELECT_LOGD_TAG_PROPERTY;
+import static com.android.settingslib.development.AbstractLogdSizePreferenceController
+ .SELECT_LOGD_TAG_SILENCE;
+
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
+import android.content.Context;
import android.os.SystemProperties;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.PreferenceScreen;
@@ -27,6 +47,7 @@ import com.android.settingslib.R;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
import com.android.settingslib.TestConfig;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,22 +66,43 @@ public class LogdSizePreferenceControllerTest {
@Mock
private PreferenceScreen mPreferenceScreen;
+ /**
+ * List Values
+ *
+ * 0: off
+ * 1: 64k
+ * 2: 256k
+ * 3: 1M
+ * 4: 4M
+ * 5: 16M
+ */
+ private String[] mListValues;
+ private String[] mListSummaries;
+ private Context mContext;
private AbstractLogdSizePreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mController = new AbstractLogdSizePreferenceController(RuntimeEnvironment.application) {};
-
+ mContext = RuntimeEnvironment.application;
+ mController = new AbstractLogdSizePreferenceController(RuntimeEnvironment.application) {
+ };
+ mListValues = mContext.getResources().getStringArray(R.array.select_logd_size_values);
+ mListSummaries = mContext.getResources().getStringArray(R.array.select_logd_size_summaries);
doReturn(mListPreference).when(mPreferenceScreen)
.findPreference(mController.getPreferenceKey());
mController.displayPreference(mPreferenceScreen);
}
+ @After
+ public void tearDown() {
+ SystemPropertiesTestImpl.clear();
+ }
+
@Test
- public void testUpateLogdSizeValues_lowRamEntries() {
- SystemProperties.set("ro.config.low_ram", "true");
+ public void testUpdateLogdSizeValues_lowRamEntries() {
+ SystemProperties.set(LOW_RAM_CONFIG_PROPERTY_KEY, "true");
mController.updateLogdSizeValues();
verify(mListPreference).setEntries(R.array.select_logd_size_lowram_titles);
}
@@ -77,4 +119,79 @@ public class LogdSizePreferenceControllerTest {
verify(mListPreference).setValue(
AbstractLogdSizePreferenceController.SELECT_LOGD_OFF_SIZE_MARKER_VALUE);
}
+
+ @Test
+ public void onPreferenceChange_noTagsSizeValueOff_shouldSetTagAndSnetTagAndSet64KSize() {
+ mController.onPreferenceChange(mListPreference, SELECT_LOGD_OFF_SIZE_MARKER_VALUE);
+
+ final String tag = SystemProperties.get(SELECT_LOGD_TAG_PROPERTY);
+ final String logSize = SystemProperties.get(SELECT_LOGD_SIZE_PROPERTY);
+ final String snetTag = SystemProperties.get(SELECT_LOGD_SNET_TAG_PROPERTY);
+
+ assertThat(tag).isEqualTo(SELECT_LOGD_TAG_SILENCE);
+ assertThat(logSize).isEqualTo(SELECT_LOGD_MINIMUM_SIZE_VALUE);
+ assertThat(snetTag).isEqualTo(DEFAULT_SNET_TAG);
+ }
+
+ @Test
+ public void onPreferenceChange_noTagsSizeValue64K_shouldNotSetTagAndSet64KSize() {
+ mController.onPreferenceChange(mListPreference, SELECT_LOGD_MINIMUM_SIZE_VALUE);
+
+ final String tag = SystemProperties.get(SELECT_LOGD_TAG_PROPERTY);
+ final String logSize = SystemProperties.get(SELECT_LOGD_SIZE_PROPERTY);
+ final String snetTag = SystemProperties.get(SELECT_LOGD_SNET_TAG_PROPERTY);
+
+ assertThat(tag).isEmpty();
+ assertThat(logSize).isEqualTo(SELECT_LOGD_MINIMUM_SIZE_VALUE);
+ assertThat(snetTag).isEmpty();
+ }
+
+ @Test
+ public void onPreferenceChange_set1M_shouldUpdateSettingLogSizeTo1M() {
+ mController.onPreferenceChange(mListPreference, mListValues[3]);
+
+ final String logSize = SystemProperties.get(SELECT_LOGD_SIZE_PROPERTY);
+
+ assertThat(logSize).isEqualTo(mListValues[3]);
+ }
+
+ @Test
+ public void onPreferenceChange_noValue_shouldUpdateSettingToEmpty() {
+ mController.onPreferenceChange(mListPreference, "" /* new value */);
+
+ final String logSize = SystemProperties.get(SELECT_LOGD_SIZE_PROPERTY);
+
+ assertThat(logSize).isEmpty();
+ }
+
+ @Test
+ public void updateLogdSizeValues_noValueSet_shouldSetDefaultTo64K() {
+ SystemProperties.set(SELECT_LOGD_SIZE_PROPERTY, "" /* new value */);
+
+ mController.updateLogdSizeValues();
+
+ verify(mListPreference).setValue(mListValues[2]);
+ verify(mListPreference).setSummary(mListSummaries[2]);
+ }
+
+ @Test
+ public void updateLogdSizeValues_noValueSetLowRamSet_shouldSetDefaultTo64K() {
+ SystemProperties.set(LOW_RAM_CONFIG_PROPERTY_KEY, Boolean.toString(true));
+ SystemProperties.set(SELECT_LOGD_SIZE_PROPERTY, "" /* new value */);
+
+ mController.updateLogdSizeValues();
+
+ verify(mListPreference).setValue(mListValues[1]);
+ verify(mListPreference).setSummary(mListSummaries[1]);
+ }
+
+ @Test
+ public void updateLogdSizeValues_64KSet_shouldSet64K() {
+ SystemProperties.set(SELECT_LOGD_SIZE_PROPERTY, mListValues[1]);
+
+ mController.updateLogdSizeValues();
+
+ verify(mListPreference).setValue(mListValues[1]);
+ verify(mListPreference).setSummary(mListSummaries[1]);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropertiesTestImpl.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropertiesTestImpl.java
index 2f89d86984f7..6977e09180c5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropertiesTestImpl.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropertiesTestImpl.java
@@ -54,4 +54,8 @@ public class SystemPropertiesTestImpl extends ShadowSystemProperties {
public static void set(String key, String val) {
sProperties.put(key, val);
}
+
+ public static synchronized void clear() {
+ sProperties.clear();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java
new file mode 100644
index 000000000000..1de7a7a9fb39
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BluetoothAddressPreferenceControllerTest {
+ @Mock
+ private Context mContext;
+ @Mock
+ private Lifecycle mLifecycle;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private Preference mPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mPreference).when(mScreen)
+ .findPreference(AbstractBluetoothAddressPreferenceController.KEY_BT_ADDRESS);
+ }
+
+ @Implements(BluetoothAdapter.class)
+ public static class ShadowEmptyBluetoothAdapter {
+ @Implementation
+ public static BluetoothAdapter getDefaultAdapter() {
+ return null;
+ }
+ }
+
+ @Test
+ @Config(shadows = ShadowEmptyBluetoothAdapter.class)
+ public void testNoBluetooth() {
+ final AbstractBluetoothAddressPreferenceController bluetoothAddressPreferenceController =
+ new ConcreteBluetoothAddressPreferenceController(mContext, mLifecycle);
+
+ assertWithMessage("Should not show pref if no bluetooth")
+ .that(bluetoothAddressPreferenceController.isAvailable())
+ .isFalse();
+ }
+
+ @Test
+ public void testHasBluetooth() {
+ final AbstractBluetoothAddressPreferenceController bluetoothAddressPreferenceController =
+ new ConcreteBluetoothAddressPreferenceController(mContext, mLifecycle);
+
+ assertWithMessage("Should show pref if bluetooth is present")
+ .that(bluetoothAddressPreferenceController.isAvailable())
+ .isTrue();
+ }
+
+ @Test
+ public void testHasBluetoothStateChangedFilter() {
+ final AbstractBluetoothAddressPreferenceController bluetoothAddressPreferenceController =
+ new ConcreteBluetoothAddressPreferenceController(mContext, mLifecycle);
+
+ assertWithMessage("Filter should have BluetoothAdapter.ACTION_STATE_CHANGED")
+ .that(bluetoothAddressPreferenceController.getConnectivityIntents())
+ .asList().contains(BluetoothAdapter.ACTION_STATE_CHANGED);
+ }
+
+ private static class ConcreteBluetoothAddressPreferenceController
+ extends AbstractBluetoothAddressPreferenceController {
+
+ public ConcreteBluetoothAddressPreferenceController(Context context,
+ Lifecycle lifecycle) {
+ super(context, lifecycle);
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java
new file mode 100644
index 000000000000..362dbd944525
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.os.Handler;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class ConnectivityPreferenceControllerTest {
+ @Mock
+ private Context mContext;
+
+ @Mock
+ private Lifecycle mLifecycle;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testBroadcastReceiver() {
+ final AbstractConnectivityPreferenceController preferenceController =
+ spy(new ConcreteConnectivityPreferenceController(mContext, mLifecycle));
+
+ final ArgumentCaptor<BroadcastReceiver> receiverArgumentCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ final ArgumentCaptor<IntentFilter> filterArgumentCaptor =
+ ArgumentCaptor.forClass(IntentFilter.class);
+
+ doReturn(new String[] {"Filter1", "Filter2"})
+ .when(preferenceController).getConnectivityIntents();
+
+ preferenceController.onStart();
+
+ verify(mContext, times(1))
+ .registerReceiver(receiverArgumentCaptor.capture(),
+ filterArgumentCaptor.capture(),
+ anyString(), nullable(Handler.class));
+
+ final BroadcastReceiver receiver = receiverArgumentCaptor.getValue();
+ final IntentFilter filter = filterArgumentCaptor.getValue();
+
+ assertWithMessage("intent filter should match 'Filter1'")
+ .that(filter.matchAction("Filter1"))
+ .isTrue();
+ assertWithMessage("intent filter should match 'Filter2'")
+ .that(filter.matchAction("Filter2"))
+ .isTrue();
+
+ preferenceController.onStop();
+
+ verify(mContext, times(1)).unregisterReceiver(receiver);
+ }
+
+ private static class ConcreteConnectivityPreferenceController
+ extends AbstractConnectivityPreferenceController {
+
+
+ public ConcreteConnectivityPreferenceController(Context context,
+ Lifecycle lifecycle) {
+ super(context, lifecycle);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return false;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return null;
+ }
+
+ @Override
+ protected String[] getConnectivityIntents() {
+ return new String[0];
+ }
+
+ @Override
+ protected void updateConnectivity() {
+
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java
new file mode 100644
index 000000000000..112ee64a6468
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.os.PersistableBundle;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class ImsStatusPreferenceControllerTest {
+ @Mock
+ private Context mContext;
+ @Mock
+ private Lifecycle mLifecycle;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private Preference mPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mPreference).when(mScreen)
+ .findPreference(AbstractImsStatusPreferenceController.KEY_IMS_REGISTRATION_STATE);
+ }
+
+ @Test
+ @Config(shadows = ShadowSubscriptionManager.class)
+ public void testIsAvailable() {
+ CarrierConfigManager carrierConfigManager = mock(CarrierConfigManager.class);
+ doReturn(carrierConfigManager).when(mContext).getSystemService(CarrierConfigManager.class);
+
+ PersistableBundle config = new PersistableBundle(1);
+ config.putBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, true);
+ doReturn(config).when(carrierConfigManager).getConfigForSubId(anyInt());
+
+ final AbstractImsStatusPreferenceController imsStatusPreferenceController =
+ new ConcreteImsStatusPreferenceController(mContext, mLifecycle);
+
+ assertWithMessage("Should be available when IMS registration is true").that(
+ imsStatusPreferenceController.isAvailable()).isTrue();
+
+ config.putBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
+
+ assertWithMessage("Should not be available when IMS registration is false")
+ .that(imsStatusPreferenceController.isAvailable()).isFalse();
+
+ doReturn(null).when(carrierConfigManager).getConfigForSubId(anyInt());
+
+ assertWithMessage("Should not be available when IMS registration is false")
+ .that(imsStatusPreferenceController.isAvailable()).isFalse();
+
+ doReturn(null).when(mContext).getSystemService(CarrierConfigManager.class);
+
+ assertWithMessage("Should not be available when CarrierConfigManager service is null")
+ .that(imsStatusPreferenceController.isAvailable()).isFalse();
+ }
+
+ @Implements(SubscriptionManager.class)
+ public static class ShadowSubscriptionManager {
+ @Implementation
+ public static int getDefaultDataSubscriptionId() {
+ return 1234;
+ }
+ }
+
+ private static class ConcreteImsStatusPreferenceController
+ extends AbstractImsStatusPreferenceController {
+
+ public ConcreteImsStatusPreferenceController(Context context,
+ Lifecycle lifecycle) {
+ super(context, lifecycle);
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java
new file mode 100644
index 000000000000..d0ecae37c849
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class IpAddressPreferenceControllerTest {
+ @Mock
+ private Context mContext;
+ @Mock
+ private Lifecycle mLifecycle;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private Preference mPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mPreference).when(mScreen)
+ .findPreference(AbstractIpAddressPreferenceController.KEY_IP_ADDRESS);
+ }
+
+ @Test
+ public void testHasIntentFilters() {
+ final AbstractIpAddressPreferenceController ipAddressPreferenceController =
+ new ConcreteIpAddressPreferenceController(mContext, mLifecycle);
+ final List<String> expectedIntents = Arrays.asList(
+ ConnectivityManager.CONNECTIVITY_ACTION,
+ WifiManager.LINK_CONFIGURATION_CHANGED_ACTION,
+ WifiManager.NETWORK_STATE_CHANGED_ACTION);
+
+
+ assertWithMessage("Intent filter should contain expected intents")
+ .that(ipAddressPreferenceController.getConnectivityIntents())
+ .asList().containsAllIn(expectedIntents);
+ }
+
+ private static class ConcreteIpAddressPreferenceController extends
+ AbstractIpAddressPreferenceController {
+
+ public ConcreteIpAddressPreferenceController(Context context,
+ Lifecycle lifecycle) {
+ super(context, lifecycle);
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java
new file mode 100644
index 000000000000..f68533ba4081
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.format.DateUtils;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowLooper;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class UptimePreferenceControllerTest {
+ @Mock
+ private Context mContext;
+ @Mock
+ private Lifecycle mLifecycle;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private Preference mPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mPreference).when(mScreen)
+ .findPreference(AbstractUptimePreferenceController.KEY_UPTIME);
+ }
+
+ @Test
+ public void testDisplayPreference() {
+ final AbstractUptimePreferenceController uptimePreferenceController =
+ new ConcreteUptimePreferenceController(mContext, mLifecycle);
+
+ uptimePreferenceController.displayPreference(mScreen);
+
+ // SystemClock is shadowed so it shouldn't advance unexpectedly while the test is running
+ verify(mPreference).setSummary(DateUtils.formatDuration(SystemClock.elapsedRealtime()));
+ }
+
+ @Test
+ public void testUptimeTick() {
+ final AbstractUptimePreferenceController uptimePreferenceController =
+ new ConcreteUptimePreferenceController(mContext, null /* lifecycle */);
+
+ uptimePreferenceController.displayPreference(mScreen);
+
+ verify(mPreference, times(1)).setSummary(any(CharSequence.class));
+
+ uptimePreferenceController.onStart();
+
+ verify(mPreference, times(2)).setSummary(any(CharSequence.class));
+
+ ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+
+ verify(mPreference, times(3)).setSummary(any(CharSequence.class));
+
+ ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+
+ verify(mPreference, times(4)).setSummary(any(CharSequence.class));
+ }
+
+ private static class ConcreteUptimePreferenceController
+ extends AbstractUptimePreferenceController {
+ public ConcreteUptimePreferenceController(Context context,
+ Lifecycle lifecycle) {
+ super(context, lifecycle);
+ }
+ }
+
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
new file mode 100644
index 000000000000..265a60b3325a
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.settingslib.deviceinfo;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settingslib.R;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import java.util.Arrays;
+import java.util.List;
+
+@SuppressLint("HardwareIds")
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class WifiMacAddressPreferenceControllerTest {
+ @Mock
+ private Context mContext;
+ @Mock
+ private Lifecycle mLifecycle;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private Preference mPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mPreference).when(mScreen)
+ .findPreference(AbstractWifiMacAddressPreferenceController.KEY_WIFI_MAC_ADDRESS);
+ }
+
+ @Test
+ public void testHasIntentFilters() {
+ final AbstractWifiMacAddressPreferenceController wifiMacAddressPreferenceController =
+ new ConcreteWifiMacAddressPreferenceController(mContext, mLifecycle);
+ final List<String> expectedIntents = Arrays.asList(
+ ConnectivityManager.CONNECTIVITY_ACTION,
+ WifiManager.LINK_CONFIGURATION_CHANGED_ACTION,
+ WifiManager.NETWORK_STATE_CHANGED_ACTION);
+
+
+ assertWithMessage("Intent filter should contain expected intents")
+ .that(wifiMacAddressPreferenceController.getConnectivityIntents())
+ .asList().containsAllIn(expectedIntents);
+ }
+
+ @Test
+ public void testWifiMacAddress() {
+ final WifiManager wifiManager = mock(WifiManager.class);
+ final WifiInfo wifiInfo = mock(WifiInfo.class);
+ doReturn("00:11:22:33:44:55").when(wifiInfo).getMacAddress();
+
+ doReturn(null).when(wifiManager).getConnectionInfo();
+ doReturn(wifiManager).when(mContext).getSystemService(WifiManager.class);
+
+ final AbstractWifiMacAddressPreferenceController wifiMacAddressPreferenceController =
+ new ConcreteWifiMacAddressPreferenceController(mContext, mLifecycle);
+
+ wifiMacAddressPreferenceController.displayPreference(mScreen);
+
+ verify(mPreference).setSummary(R.string.status_unavailable);
+
+ doReturn(wifiInfo).when(wifiManager).getConnectionInfo();
+
+ wifiMacAddressPreferenceController.displayPreference(mScreen);
+
+ verify(mPreference).setSummary("00:11:22:33:44:55");
+ }
+
+ private static class ConcreteWifiMacAddressPreferenceController
+ extends AbstractWifiMacAddressPreferenceController {
+
+ public ConcreteWifiMacAddressPreferenceController(Context context,
+ Lifecycle lifecycle) {
+ super(context, lifecycle);
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 3e90435b21d7..dad3a28f3638 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.RuntimeEnvironment.application;
+import static org.robolectric.shadow.api.Shadow.extract;
import android.app.ActivityManager;
import android.content.ContentResolver;
@@ -66,7 +67,6 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
-import org.robolectric.internal.ShadowExtractor;
import java.util.ArrayList;
import java.util.Collections;
@@ -79,7 +79,6 @@ import java.util.Map;
shadows = {TileUtilsTest.TileUtilsShadowRemoteViews.class})
public class TileUtilsTest {
- @Mock
private Context mContext;
@Mock
private PackageManager mPackageManager;
@@ -97,6 +96,7 @@ public class TileUtilsTest {
@Before
public void setUp() throws NameNotFoundException {
+ mContext = spy(application);
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources);
@@ -456,8 +456,7 @@ public class TileUtilsTest {
assertThat(tile.remoteViews).isNotNull();
assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
// Make sure the summary TextView got a new text string.
- TileUtilsShadowRemoteViews shadowRemoteViews =
- (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews);
+ TileUtilsShadowRemoteViews shadowRemoteViews = extract(tile.remoteViews);
assertThat(shadowRemoteViews.overrideViewId).isEqualTo(android.R.id.summary);
assertThat(shadowRemoteViews.overrideText).isEqualTo("new summary text");
}
@@ -494,8 +493,7 @@ public class TileUtilsTest {
assertThat(tile.remoteViews).isNotNull();
assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
// Make sure the summary TextView didn't get any text view updates.
- TileUtilsShadowRemoteViews shadowRemoteViews =
- (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews);
+ TileUtilsShadowRemoteViews shadowRemoteViews = extract(tile.remoteViews);
assertThat(shadowRemoteViews.overrideViewId).isNull();
assertThat(shadowRemoteViews.overrideText).isNull();
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java
index f31d2e1afcd8..db599a776d23 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java
@@ -18,8 +18,11 @@ package com.android.settingslib.suggestions;
import static com.google.common.truth.Truth.assertThat;
+import static org.robolectric.RuntimeEnvironment.application;
+import static org.robolectric.shadow.api.Shadow.extract;
+
+import android.app.ApplicationPackageManager;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ResolveInfo;
@@ -34,22 +37,21 @@ import com.android.settingslib.drawer.TileUtilsTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import org.robolectric.res.ResourceLoader;
-import org.robolectric.res.builder.DefaultPackageManager;
-import org.robolectric.res.builder.RobolectricPackageManager;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowApplicationPackageManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
+ shadows = SuggestionParserTest.TestPackageManager.class)
public class SuggestionParserTest {
- private Context mContext;
- private RobolectricPackageManager mPackageManager;
+ private TestPackageManager mPackageManager;
private SuggestionParser mSuggestionParser;
private SuggestionCategory mMultipleCategory;
private SuggestionCategory mExclusiveCategory;
@@ -61,11 +63,8 @@ public class SuggestionParserTest {
@Before
public void setUp() {
- RuntimeEnvironment.setRobolectricPackageManager(
- new TestPackageManager(RuntimeEnvironment.getAppResourceLoader()));
- mContext = RuntimeEnvironment.application;
- mPackageManager = RuntimeEnvironment.getRobolectricPackageManager();
- mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+ mPackageManager = extract(application.getPackageManager());
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(application);
mSuggestion = new Tile();
mSuggestion.intent = new Intent("action");
mSuggestion.intent.setComponent(new ComponentName("pkg", "cls"));
@@ -81,7 +80,7 @@ public class SuggestionParserTest {
mExpiredExclusiveCategory.exclusive = true;
mExpiredExclusiveCategory.exclusiveExpireDaysInMillis = 0;
- mSuggestionParser = new SuggestionParser(mContext, mPrefs,
+ mSuggestionParser = new SuggestionParser(application, mPrefs,
Arrays.asList(mMultipleCategory, mExclusiveCategory, mExpiredExclusiveCategory),
"0");
@@ -199,7 +198,7 @@ public class SuggestionParserTest {
final Tile suggestion = mSuggestionsBeforeDismiss.get(0);
if (mSuggestionParser.dismissSuggestion(suggestion)) {
- RuntimeEnvironment.getRobolectricPackageManager().removeResolveInfosForIntent(
+ mPackageManager.removeResolveInfosForIntent(
new Intent(Intent.ACTION_MAIN).addCategory(mMultipleCategory.category),
suggestion.intent.getComponent().getPackageName());
}
@@ -207,13 +206,10 @@ public class SuggestionParserTest {
mMultipleCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled);
}
- private static class TestPackageManager extends DefaultPackageManager {
-
- TestPackageManager(ResourceLoader appResourceLoader) {
- super(appResourceLoader);
- }
+ @Implements(ApplicationPackageManager.class)
+ public static class TestPackageManager extends ShadowApplicationPackageManager {
- @Override
+ @Implementation
public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) {
return super.queryIntentActivities(intent, flags);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/SettingsLibShadowResources.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/SettingsLibShadowResources.java
index a376dcdbbbd3..b53cc371c641 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/SettingsLibShadowResources.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/SettingsLibShadowResources.java
@@ -16,7 +16,7 @@
package com.android.settingslib.testutils.shadow;
-import static org.robolectric.internal.Shadow.directlyOn;
+import static org.robolectric.shadow.api.Shadow.directlyOn;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java
index 1f633da4644a..95ff13b45fb9 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java
@@ -29,6 +29,9 @@ public interface GlobalActions extends Plugin {
default void showShutdownUi(boolean isReboot, String reason) {
}
+ default void destroy() {
+ }
+
@ProvidesInterface(version = GlobalActionsManager.VERSION)
public interface GlobalActionsManager {
int VERSION = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index dc626fb4df65..851b78cfcd49 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -84,9 +84,6 @@ public class DozeUi implements DozeMachine.Part {
case DOZE_REQUEST_PULSE:
pulseWhileDozing(mMachine.getPulseReason());
break;
- case DOZE_PULSE_DONE:
- mHost.abortPulsing();
- break;
case INITIALIZED:
mHost.startDozing();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
index 09a08f09fc9a..f06cda0f787a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
@@ -31,6 +31,7 @@ import android.os.ServiceManager;
public class GlobalActionsComponent extends SystemUI implements Callbacks, GlobalActionsManager {
+ private GlobalActions mPlugin;
private Extension<GlobalActions> mExtension;
private IStatusBarService mBarService;
@@ -41,10 +42,19 @@ public class GlobalActionsComponent extends SystemUI implements Callbacks, Globa
mExtension = Dependency.get(ExtensionController.class).newExtension(GlobalActions.class)
.withPlugin(GlobalActions.class)
.withDefault(() -> new GlobalActionsImpl(mContext))
+ .withCallback(this::onExtensionCallback)
.build();
+ mPlugin = mExtension.get();
SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
}
+ private void onExtensionCallback(GlobalActions newPlugin) {
+ if (mPlugin != null) {
+ mPlugin.destroy();
+ }
+ mPlugin = newPlugin;
+ }
+
@Override
public void handleShowShutdownUi(boolean isReboot, String reason) {
mExtension.get().showShutdownUi(isReboot, reason);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 189badfc42fc..d82f9cd44e4a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -16,27 +16,6 @@ package com.android.systemui.globalactions;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
-import com.android.internal.R;
-import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.util.EmergencyAffordanceManager;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.Dependency;
-import com.android.systemui.HardwareUiLayout;
-import com.android.systemui.Interpolators;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
-import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.phone.ScrimController;
-import com.android.systemui.volume.VolumeDialogMotion.LogAccelerateInterpolator;
-import com.android.systemui.volume.VolumeDialogMotion.LogDecelerateInterpolator;
-
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.ActivityManager;
import android.app.Dialog;
import android.app.WallpaperManager;
@@ -69,7 +48,6 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
-import android.util.MathUtils;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
@@ -86,7 +64,23 @@ import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.internal.R;
+import com.android.internal.colorextraction.ColorExtractor;
+import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.colorextraction.drawable.GradientDrawable;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.util.EmergencyAffordanceManager;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.Dependency;
+import com.android.systemui.HardwareUiLayout;
+import com.android.systemui.Interpolators;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.volume.VolumeDialogMotion.LogAccelerateInterpolator;
import java.util.ArrayList;
import java.util.List;
@@ -96,7 +90,8 @@ import java.util.List;
* may show depending on whether the keyguard is showing, and whether the device
* is provisioned.
*/
-class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
+class GlobalActionsDialog implements DialogInterface.OnDismissListener,
+ DialogInterface.OnClickListener {
static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
@@ -195,6 +190,14 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn
}
}
+ /**
+ * Dismiss the global actions dialog, if it's currently shown
+ */
+ public void dismissDialog() {
+ mHandler.removeMessages(MESSAGE_DISMISS);
+ mHandler.sendEmptyMessage(MESSAGE_DISMISS);
+ }
+
private void awakenIfNecessary() {
if (mDreamManager != null) {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 2cf230c8e12d..35634374d5dd 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -14,12 +14,12 @@
package com.android.systemui.globalactions;
+import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
+
import android.app.Dialog;
import android.app.KeyguardManager;
-import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.Context;
-import android.graphics.Color;
import android.graphics.Point;
import android.view.ViewGroup;
import android.view.Window;
@@ -32,12 +32,14 @@ import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.colorextraction.drawable.GradientDrawable;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
+import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
-public class GlobalActionsImpl implements GlobalActions {
+public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks {
private static final float SHUTDOWN_SCRIM_ALPHA = 0.95f;
@@ -45,15 +47,23 @@ public class GlobalActionsImpl implements GlobalActions {
private final KeyguardMonitor mKeyguardMonitor;
private final DeviceProvisionedController mDeviceProvisionedController;
private GlobalActionsDialog mGlobalActions;
+ private boolean mDisabled;
public GlobalActionsImpl(Context context) {
mContext = context;
mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+ SysUiServiceProvider.getComponent(context, CommandQueue.class).addCallbacks(this);
+ }
+
+ @Override
+ public void destroy() {
+ SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallbacks(this);
}
@Override
public void showGlobalActions(GlobalActionsManager manager) {
+ if (mDisabled) return;
if (mGlobalActions == null) {
mGlobalActions = new GlobalActionsDialog(mContext, manager);
}
@@ -107,4 +117,14 @@ public class GlobalActionsImpl implements GlobalActions {
d.show();
}
+
+ @Override
+ public void disable(int state1, int state2, boolean animate) {
+ final boolean disabled = (state2 & DISABLE2_GLOBAL_ACTIONS) != 0;
+ if (disabled == mDisabled) return;
+ mDisabled = disabled;
+ if (disabled && mGlobalActions != null) {
+ mGlobalActions.dismissDialog();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
index b83590979ef7..5ec3dff0043c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
@@ -23,7 +23,7 @@ import android.os.Handler;
*/
public class DelayedWakeLock implements WakeLock {
- private static final long RELEASE_DELAY_MS = 100;
+ private static final long RELEASE_DELAY_MS = 120;
private final Handler mHandler;
private final WakeLock mInner;
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index e17a6a6aefa9..4834f3893240 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4665,6 +4665,9 @@ message MetricsEvent {
// OS: P
DIALOG_CLEAR_ADB_KEYS = 1223;
+ // Open: Settings > Developer options > Quick setting tile config
+ DEVELOPMENT_QS_TILE_CONFIG = 1224;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0b2dd9b8d5e3..26401a7bbf9f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12939,6 +12939,10 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new IllegalArgumentException("Provided bugreport type is not correct, value: "
+ bugreportType);
}
+ // Always log caller, even if it does not have permission to dump.
+ String type = extraOptions == null ? "bugreport" : extraOptions;
+ Slog.i(TAG, type + " requested by UID " + Binder.getCallingUid());
+
enforceCallingPermission(android.Manifest.permission.DUMP, "requestBugReport");
if (extraOptions != null) {
SystemProperties.set("dumpstate.options", extraOptions);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 5583e86cde70..d7cd81ff3c5f 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1371,6 +1371,7 @@ public class Tethering extends BaseNetworkObserver {
sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
}
}
+ mUpstreamNetworkMonitor.setCurrentUpstream((ns != null) ? ns.network : null);
setUpstreamNetwork(ns);
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index c5f752807cb7..b35ed75106b3 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -95,7 +95,10 @@ public class UpstreamNetworkMonitor {
private NetworkCallback mDefaultNetworkCallback;
private NetworkCallback mMobileNetworkCallback;
private boolean mDunRequired;
- private Network mCurrentDefault;
+ // The current system default network (not really used yet).
+ private Network mDefaultInternetNetwork;
+ // The current upstream network used for tethering.
+ private Network mTetheringUpstreamNetwork;
public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) {
mContext = ctx;
@@ -130,10 +133,12 @@ public class UpstreamNetworkMonitor {
releaseCallback(mDefaultNetworkCallback);
mDefaultNetworkCallback = null;
+ mDefaultInternetNetwork = null;
releaseCallback(mListenAllCallback);
mListenAllCallback = null;
+ mTetheringUpstreamNetwork = null;
mNetworkMap.clear();
}
@@ -207,7 +212,7 @@ public class UpstreamNetworkMonitor {
break;
default:
/* If we've found an active upstream connection that's not DUN/HIPRI
- * we should stop any outstanding DUN/HIPRI start requests.
+ * we should stop any outstanding DUN/HIPRI requests.
*
* If we found NONE we don't want to do this as we want any previous
* requests to keep trying to bring up something we can use.
@@ -219,6 +224,10 @@ public class UpstreamNetworkMonitor {
return typeStatePair.ns;
}
+ public void setCurrentUpstream(Network upstream) {
+ mTetheringUpstreamNetwork = upstream;
+ }
+
public Set<IpPrefix> getLocalPrefixes() {
return (Set<IpPrefix>) mLocalPrefixes.clone();
}
@@ -250,7 +259,7 @@ public class UpstreamNetworkMonitor {
// These request*() calls can be deleted post oag/339444.
return;
}
- mCurrentDefault = network;
+ mDefaultInternetNetwork = network;
break;
case CALLBACK_MOBILE_REQUEST:
@@ -302,6 +311,13 @@ public class UpstreamNetworkMonitor {
network, newNc));
}
+ // Log changes in upstream network signal strength, if available.
+ if (network.equals(mTetheringUpstreamNetwork) && newNc.hasSignalStrength()) {
+ final int newSignal = newNc.getSignalStrength();
+ final String prevSignal = getSignalStrength(prev.networkCapabilities);
+ mLog.logf("upstream network signal strength: %s -> %s", prevSignal, newSignal);
+ }
+
mNetworkMap.put(network, new NetworkState(
null, prev.linkProperties, newNc, network, null, null));
// TODO: If sufficient information is available to select a more
@@ -330,9 +346,21 @@ public class UpstreamNetworkMonitor {
notifyTarget(EVENT_ON_LINKPROPERTIES, network);
}
+ private void handleSuspended(int callbackType, Network network) {
+ if (callbackType != CALLBACK_LISTEN_ALL) return;
+ if (!network.equals(mTetheringUpstreamNetwork)) return;
+ mLog.log("SUSPENDED current upstream: " + network);
+ }
+
+ private void handleResumed(int callbackType, Network network) {
+ if (callbackType != CALLBACK_LISTEN_ALL) return;
+ if (!network.equals(mTetheringUpstreamNetwork)) return;
+ mLog.log("RESUMED current upstream: " + network);
+ }
+
private void handleLost(int callbackType, Network network) {
if (callbackType == CALLBACK_TRACK_DEFAULT) {
- mCurrentDefault = null;
+ mDefaultInternetNetwork = null;
// Receiving onLost() for a default network does not necessarily
// mean the network is gone. We wait for a separate notification
// on either the LISTEN_ALL or MOBILE_REQUEST callbacks before
@@ -401,8 +429,15 @@ public class UpstreamNetworkMonitor {
recomputeLocalPrefixes();
}
- // TODO: Handle onNetworkSuspended();
- // TODO: Handle onNetworkResumed();
+ @Override
+ public void onNetworkSuspended(Network network) {
+ handleSuspended(mCallbackType, network);
+ }
+
+ @Override
+ public void onNetworkResumed(Network network) {
+ handleResumed(mCallbackType, network);
+ }
@Override
public void onLost(Network network) {
@@ -467,4 +502,9 @@ public class UpstreamNetworkMonitor {
return prefixSet;
}
+
+ private static String getSignalStrength(NetworkCapabilities nc) {
+ if (nc == null || !nc.hasSignalStrength()) return "unknown";
+ return Integer.toString(nc.getSignalStrength());
+ }
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 9aabdab7daa8..9a6e609445a5 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -29,6 +29,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.Trace;
import android.text.format.DateUtils;
import android.util.EventLog;
import android.util.MathUtils;
@@ -304,6 +305,7 @@ class AutomaticBrightnessController {
}
private void handleLightSensorEvent(long time, float lux) {
+ Trace.traceCounter(Trace.TRACE_TAG_POWER, "ALS", (int) lux);
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
if (mAmbientLightRingBuffer.size() == 0) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f8e58362e7ae..f930b523e626 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -683,8 +683,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Configure auto-brightness.
boolean autoBrightnessEnabled = false;
if (mAutomaticBrightnessController != null) {
- final boolean autoBrightnessEnabledInDoze = mAllowAutoBrightnessWhileDozingConfig
- && (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND);
+ final boolean autoBrightnessEnabledInDoze =
+ mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state);
autoBrightnessEnabled = mPowerRequest.useAutoBrightness
&& (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
&& brightness < 0;
@@ -726,8 +726,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
// Use default brightness when dozing unless overridden.
- if (brightness < 0 && (state == Display.STATE_DOZE
- || state == Display.STATE_DOZE_SUSPEND)) {
+ if (brightness < 0 && Display.isDozeState(state)) {
brightness = mScreenBrightnessDozeConfig;
}
@@ -777,7 +776,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Skip the animation when the screen is off or suspended or transition to/from VR.
if (!mPendingScreenOff) {
if (mSkipScreenOnBrightnessRamp) {
-
if (state == Display.STATE_ON) {
if (mSkipRampState == RAMP_STATE_SKIP_NONE && mDozing) {
mInitialAutoBrightness = brightness;
@@ -794,15 +792,25 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
- boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR);
- if ((state == Display.STATE_ON
- && mSkipRampState == RAMP_STATE_SKIP_NONE
- || state == Display.STATE_DOZE && !mBrightnessBucketsInDozeConfig)
- && !wasOrWillBeInVr) {
+ final boolean wasOrWillBeInVr =
+ (state == Display.STATE_VR || oldState == Display.STATE_VR);
+ final boolean initialRampSkip =
+ state == Display.STATE_ON && mSkipRampState != RAMP_STATE_SKIP_NONE;
+ // While dozing, sometimes the brightness is split into buckets. Rather than animating
+ // through the buckets, which is unlikely to be smooth in the first place, just jump
+ // right to the suggested brightness.
+ final boolean hasBrightnessBuckets =
+ Display.isDozeState(state) && mBrightnessBucketsInDozeConfig;
+ // If the color fade is totally covering the screen then we can change the backlight
+ // level without it being a noticeable jump since any actual content isn't yet visible.
+ final boolean isDisplayContentVisible =
+ mColorFadeEnabled && mPowerState.getColorFadeLevel() == 1.0f;
+ if (initialRampSkip || hasBrightnessBuckets
+ || wasOrWillBeInVr || !isDisplayContentVisible) {
+ animateScreenBrightness(brightness, 0);
+ } else {
animateScreenBrightness(brightness,
slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
- } else {
- animateScreenBrightness(brightness, 0);
}
}
@@ -925,6 +933,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
if (!reportOnly) {
+ Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenState", state);
mPowerState.setScreenState(state);
// Tell battery stats about the transition.
try {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 261ae9018414..d7329dbf0e4c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3365,7 +3365,9 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isUpgrade() {
// allow instant applications
- return mIsUpgrade;
+ // The system property allows testing ota flow when upgraded to the same image.
+ return mIsUpgrade || SystemProperties.getBoolean(
+ "persist.pm.mock-upgrade", false /* default */);
}
private @Nullable String getRequiredButNotReallyRequiredVerifierLPr() {
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 342ec4b79fed..7a2e630cfdac 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -58,6 +58,9 @@ class GlobalActions implements GlobalActionsListener {
public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {
if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);
+ if (mStatusBarInternal.isGlobalActionsDisabled()) {
+ return;
+ }
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = deviceProvisioned;
mShowing = true;
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index f1fb3e7b4915..6a5ecfaa7c47 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -20,15 +20,25 @@ import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.IntentFilter;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.IStatsCompanionService;
import android.os.IStatsManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Slog;
+import java.util.ArrayList;
+import java.util.List;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.KernelWakelockReader;
import com.android.internal.os.KernelWakelockStats;
@@ -53,6 +63,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private final PendingIntent mAnomalyAlarmIntent;
private final PendingIntent mPollingAlarmIntent;
+ private final BroadcastReceiver mAppUpdateReceiver;
public StatsCompanionService(Context context) {
super();
@@ -63,8 +74,85 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
new Intent(mContext, AnomalyAlarmReceiver.class), 0);
mPollingAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
new Intent(mContext, PollingAlarmReceiver.class), 0);
+ mAppUpdateReceiver = new AppUpdateReceiver();
+ Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED.");
}
+ private final static int[] toIntArray(List<Integer> list){
+ int[] ret = new int[list.size()];
+ for(int i = 0;i < ret.length;i++) {
+ ret[i] = list.get(i);
+ }
+ return ret;
+ }
+
+ // Assumes that sStatsdLock is held.
+ private final void informAllUidsLocked(Context context) throws RemoteException {
+ UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ PackageManager pm = context.getPackageManager();
+ final List<UserInfo> users = um.getUsers(true);
+ if (DEBUG) {
+ Slog.w(TAG, "Iterating over "+users.size() + " profiles.");
+ }
+
+ List<Integer> uids = new ArrayList();
+ List<Integer> versions = new ArrayList();
+ List<String> apps = new ArrayList();
+
+ // Add in all the apps for every user/profile.
+ for (UserInfo profile : users) {
+ List<PackageInfo> pi = pm.getInstalledPackagesAsUser(0, profile.id);
+ for (int j = 0; j < pi.size(); j++) {
+ if (pi.get(j).applicationInfo != null) {
+ uids.add(pi.get(j).applicationInfo.uid);
+ versions.add(pi.get(j).versionCode);
+ apps.add(pi.get(j).packageName);
+ }
+ }
+ }
+ sStatsd.informAllUidData(toIntArray(uids), toIntArray(versions), apps.toArray(new
+ String[apps.size()]));
+ if (DEBUG) {
+ Slog.w(TAG, "Sent data for "+uids.size() +" apps");
+ }
+ }
+
+ public final static class AppUpdateReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
+ synchronized (sStatsdLock) {
+ if (sStatsd == null) {
+ Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+ return;
+ }
+ try {
+ if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
+ Bundle b = intent.getExtras();
+ int uid = b.getInt(Intent.EXTRA_UID);
+ boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+ if (!replacing) {
+ // Don't bother sending an update if we're right about to get another
+ // intent for the new version that's added.
+ PackageManager pm = context.getPackageManager();
+ String app = intent.getData().getSchemeSpecificPart();
+ sStatsd.informOnePackageRemoved(app, uid);
+ }
+ } else {
+ PackageManager pm = context.getPackageManager();
+ Bundle b = intent.getExtras();
+ int uid = b.getInt(Intent.EXTRA_UID);
+ String app = intent.getData().getSchemeSpecificPart();
+ PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER);
+ sStatsd.informOnePackage(app, uid, pi.versionCode);
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to inform statsd of an app update", e);
+ }
+ }
+ }
+ };
+
public final static class AnomalyAlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -275,6 +363,15 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
forgetEverything();
}
+ // Setup broadcast receiver for updates
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiverAsUser(mAppUpdateReceiver, UserHandle.ALL, filter, null,
+ null);
+ // Pull the latest state of UID->app name, version mapping when statsd starts.
+ informAllUidsLocked(mContext);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
forgetEverything();
@@ -293,6 +390,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private void forgetEverything() {
synchronized (sStatsdLock) {
sStatsd = null;
+ mContext.unregisterReceiver(mAppUpdateReceiver);
cancelAnomalyAlarm();
cancelPollingAlarms();
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 0884678478f6..b07fe98d806e 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -77,6 +77,7 @@ public interface StatusBarManagerInternal {
void setCurrentUser(int newUserId);
+ boolean isGlobalActionsDisabled();
void setGlobalActionsListener(GlobalActionsListener listener);
void showGlobalActions();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index bdfbe48153df..c78a3406d0ac 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.statusbar;
+import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
+
import android.app.ActivityThread;
import android.app.StatusBarManager;
import android.content.ComponentName;
@@ -363,6 +365,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
@Override
+ public boolean isGlobalActionsDisabled() {
+ return (mDisabled2 & DISABLE2_GLOBAL_ACTIONS) != 0;
+ }
+
+ @Override
public void setGlobalActionsListener(GlobalActionsListener listener) {
mGlobalActionListener = listener;
mGlobalActionListener.onStatusBarConnectedChanged(mBar != null);
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 6117da7b1a38..c1607e94dd1e 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -1022,20 +1022,6 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
- @Override
- public boolean dispatchKeyEventToHdmi(KeyEvent event) throws RemoteException {
- synchronized (mImplLock) {
- if (mReleased) {
- throw new IllegalStateException("Device already released.");
- }
- }
- if (mInfo.getType() != TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) {
- return false;
- }
- // TODO(hdmi): mHdmiClient.sendKeyEvent(event);
- return false;
- }
-
private boolean startCapture(Surface surface, TvStreamConfig config) {
synchronized (mImplLock) {
if (mReleased) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0e68a8f64e5f..0b65b2287bdd 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -119,6 +119,7 @@ import static com.android.server.wm.proto.DisplayProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.app.ActivityManager.StackId;
+import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -3571,6 +3572,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
final int orientation = super.getOrientation();
+ boolean isCar = mService.mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE);
+ if (isCar) {
+ // In a car, you cannot physically rotate the screen, so it doesn't make sense to
+ // allow anything but the default orientation.
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
+ "Forcing UNSPECIFIED orientation in car. Ignoring " + orientation);
+ return SCREEN_ORIENTATION_UNSPECIFIED;
+ }
+
if (orientation != SCREEN_ORIENTATION_UNSET
&& orientation != SCREEN_ORIENTATION_BEHIND) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
index 0230f36b6fa0..1925c39e5211 100644
--- a/services/net/java/android/net/ip/ConnectivityPacketTracker.java
+++ b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.system.ErrnoException;
import android.system.Os;
import android.system.PacketSocketAddress;
+import android.text.TextUtils;
import android.util.Log;
import android.util.LocalLog;
@@ -59,11 +60,14 @@ public class ConnectivityPacketTracker {
private static final boolean DBG = false;
private static final String MARK_START = "--- START ---";
private static final String MARK_STOP = "--- STOP ---";
+ private static final String MARK_NAMED_START = "--- START (%s) ---";
+ private static final String MARK_NAMED_STOP = "--- STOP (%s) ---";
private final String mTag;
private final LocalLog mLog;
private final BlockingSocketReader mPacketListener;
private boolean mRunning;
+ private String mDisplayName;
public ConnectivityPacketTracker(Handler h, NetworkInterface netif, LocalLog log) {
final String ifname;
@@ -85,14 +89,16 @@ public class ConnectivityPacketTracker {
mPacketListener = new PacketListener(h, ifindex, hwaddr, mtu);
}
- public void start() {
+ public void start(String displayName) {
mRunning = true;
+ mDisplayName = displayName;
mPacketListener.start();
}
public void stop() {
mPacketListener.stop();
mRunning = false;
+ mDisplayName = null;
}
private final class PacketListener extends BlockingSocketReader {
@@ -133,16 +139,19 @@ public class ConnectivityPacketTracker {
@Override
protected void onStart() {
- mLog.log(MARK_START);
+ final String msg = TextUtils.isEmpty(mDisplayName)
+ ? MARK_START
+ : String.format(MARK_NAMED_START, mDisplayName);
+ mLog.log(msg);
}
@Override
protected void onStop() {
- if (mRunning) {
- mLog.log(MARK_STOP);
- } else {
- mLog.log(MARK_STOP + " (packet listener stopped unexpectedly)");
- }
+ String msg = TextUtils.isEmpty(mDisplayName)
+ ? MARK_STOP
+ : String.format(MARK_NAMED_STOP, mDisplayName);
+ if (!mRunning) msg += " (packet listener stopped unexpectedly)";
+ mLog.log(msg);
}
@Override
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index bc07b8108631..e33f6c99aea8 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -26,6 +26,7 @@ import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties.ProvisioningChange;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
@@ -348,6 +349,16 @@ public class IpManager extends StateMachine {
return this;
}
+ public Builder withNetwork(Network network) {
+ mConfig.mNetwork = network;
+ return this;
+ }
+
+ public Builder withDisplayName(String displayName) {
+ mConfig.mDisplayName = displayName;
+ return this;
+ }
+
public ProvisioningConfiguration build() {
return new ProvisioningConfiguration(mConfig);
}
@@ -362,6 +373,8 @@ public class IpManager extends StateMachine {
/* package */ ApfCapabilities mApfCapabilities;
/* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
/* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
+ /* package */ Network mNetwork = null;
+ /* package */ String mDisplayName = null;
public ProvisioningConfiguration() {} // used by Builder
@@ -374,6 +387,9 @@ public class IpManager extends StateMachine {
mStaticIpConfig = other.mStaticIpConfig;
mApfCapabilities = other.mApfCapabilities;
mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
+ mIPv6AddrGenMode = other.mIPv6AddrGenMode;
+ mNetwork = other.mNetwork;
+ mDisplayName = other.mDisplayName;
}
@Override
@@ -388,6 +404,8 @@ public class IpManager extends StateMachine {
.add("mApfCapabilities: " + mApfCapabilities)
.add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
.add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
+ .add("mNetwork: " + mNetwork)
+ .add("mDisplayName: " + mDisplayName)
.toString();
}
@@ -1441,10 +1459,10 @@ public class IpManager extends StateMachine {
@Override
public void enter() {
// Get the Configuration for ApfFilter from Context
- boolean filter802_3Frames =
+ final boolean filter802_3Frames =
mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
- int[] ethTypeBlackList = mContext.getResources().getIntArray(
+ final int[] ethTypeBlackList = mContext.getResources().getIntArray(
R.array.config_apfEthTypeBlackList);
mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
@@ -1456,7 +1474,7 @@ public class IpManager extends StateMachine {
}
mPacketTracker = createPacketTracker();
- if (mPacketTracker != null) mPacketTracker.start();
+ if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
if (mConfiguration.mEnableIPv6 && !startIPv6()) {
doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
@@ -1470,7 +1488,7 @@ public class IpManager extends StateMachine {
return;
}
- InitialConfiguration config = mConfiguration.mInitialConfig;
+ final InitialConfiguration config = mConfiguration.mInitialConfig;
if ((config != null) && !applyInitialConfig(config)) {
// TODO introduce a new IpManagerEvent constant to distinguish this error case.
doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
index 343d237f8cd9..bbd3d13efbd6 100644
--- a/services/net/java/android/net/util/SharedLog.java
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -106,6 +106,10 @@ public class SharedLog {
record(Category.NONE, msg);
}
+ public void logf(String fmt, Object... args) {
+ log(String.format(fmt, args));
+ }
+
public void mark(String msg) {
record(Category.MARK, msg);
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 1f6dda191d91..cc8bd69eac3f 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -55,10 +55,6 @@ public class ActivityTestsBase {
private final Context mContext = InstrumentationRegistry.getContext();
private HandlerThread mHandlerThread;
- // Grabbing an instance of {@link WindowManagerService} creates it if not present so this must
- // be called at before any tests.
- private final WindowManagerService mWms = WindowTestUtils.getWindowManagerService(mContext);
-
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -136,7 +132,7 @@ public class ActivityTestsBase {
mSupportsSplitScreenMultiWindow = true;
mSupportsFreeformWindowManagement = true;
mSupportsPictureInPicture = true;
- mWindowManager = WindowTestUtils.getWindowManagerService(context);
+ mWindowManager = WindowTestUtils.getMockWindowManagerService();
}
@Override