diff options
297 files changed, 7429 insertions, 3320 deletions
diff --git a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java index 7a32c0ccda07..e2b75c3f5746 100644 --- a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java +++ b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java @@ -118,6 +118,52 @@ public class SQLiteDatabasePerfTest { } @Test + public void testCursorIterateForward() { + // A larger dataset is needed to exceed default CursorWindow size + int datasetSize = DEFAULT_DATASET_SIZE * 50; + insertT1TestDataSet(datasetSize); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + try (Cursor cursor = mDatabase + .rawQuery("SELECT _ID, COL_A, COL_B, COL_C FROM T1 ORDER BY _ID", null)) { + int i = 0; + while(cursor.moveToNext()) { + assertEquals(i, cursor.getInt(0)); + assertEquals(i, cursor.getInt(1)); + assertEquals("T1Value" + i, cursor.getString(2)); + assertEquals(1.1 * i, cursor.getDouble(3), 0.0000001d); + i++; + } + assertEquals(datasetSize, i); + } + } + } + + @Test + public void testCursorIterateBackwards() { + // A larger dataset is needed to exceed default CursorWindow size + int datasetSize = DEFAULT_DATASET_SIZE * 50; + insertT1TestDataSet(datasetSize); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + try (Cursor cursor = mDatabase + .rawQuery("SELECT _ID, COL_A, COL_B, COL_C FROM T1 ORDER BY _ID", null)) { + int i = datasetSize - 1; + while(cursor.moveToPosition(i)) { + assertEquals(i, cursor.getInt(0)); + assertEquals(i, cursor.getInt(1)); + assertEquals("T1Value" + i, cursor.getString(2)); + assertEquals(1.1 * i, cursor.getDouble(3), 0.0000001d); + i--; + } + assertEquals(-1, i); + } + } + } + + @Test public void testInnerJoin() { mDatabase.setForeignKeyConstraintsEnabled(true); mDatabase.beginTransaction(); @@ -201,8 +247,12 @@ public class SQLiteDatabasePerfTest { } private void insertT1TestDataSet() { + insertT1TestDataSet(DEFAULT_DATASET_SIZE); + } + + private void insertT1TestDataSet(int size) { mDatabase.beginTransaction(); - for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) { + for (int i = 0; i < size; i++) { mDatabase.execSQL("INSERT INTO T1 VALUES (?, ?, ?, ?)", new Object[]{i, i, "T1Value" + i, i * 1.1}); } diff --git a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java index dccb34be9d07..fefda64b51a7 100644 --- a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java +++ b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java @@ -76,7 +76,7 @@ public class TextPerfUtils { } SpannableStringBuilder ssb = new SpannableStringBuilder(cs); - for (int i = 0; i < ssb.length(); i += wordLen) { + for (int i = 0; i < ssb.length(); i += wordLen + 1) { final int spanStart = i; final int spanEnd = (i + wordLen) > ssb.length() ? ssb.length() : i + wordLen; diff --git a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java index 55b97e7675fd..dc34b7fe057c 100644 --- a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java @@ -117,6 +117,26 @@ public class TextViewPrecomputedTextPerfTest { } @Test + public void testNewLayout_RandomText_Selectable() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + BoringLayout.Metrics metrics = new BoringLayout.Metrics(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final TextView textView = new TextView(getContext()); + textView.setTextIsSelectable(true); + textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED); + textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL); + textView.setText(text); + Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + textView.makeNewLayout(TEXT_WIDTH, TEXT_WIDTH, UNKNOWN_BORING, UNKNOWN_BORING, + TEXT_WIDTH, false); + } + } + + @Test public void testNewLayout_PrecomputedText() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); BoringLayout.Metrics metrics = new BoringLayout.Metrics(); @@ -179,6 +199,24 @@ public class TextViewPrecomputedTextPerfTest { } @Test + public void testSetText_RandomText_Selectable() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + BoringLayout.Metrics metrics = new BoringLayout.Metrics(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final TextView textView = new TextView(getContext()); + textView.setTextIsSelectable(true); + textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED); + textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL); + Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + textView.setText(text); + } + } + + @Test public void testSetText_PrecomputedText() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); BoringLayout.Metrics metrics = new BoringLayout.Metrics(); @@ -222,8 +260,8 @@ public class TextViewPrecomputedTextPerfTest { @Test public void testOnMeasure_RandomText() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH); - int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0); + int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST); + int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); while (state.keepRunning()) { state.pauseTiming(); final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); @@ -240,10 +278,31 @@ public class TextViewPrecomputedTextPerfTest { } @Test + public void testOnMeasure_RandomText_Selectable() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST); + int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final TestableTextView textView = new TestableTextView(getContext()); + textView.setTextIsSelectable(true); + textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED); + textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL); + textView.setText(text); + textView.nullLayouts(); + Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + textView.onMeasure(width, height); + } + } + + @Test public void testOnMeasure_PrecomputedText() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH); - int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0); + int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST); + int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); while (state.keepRunning()) { state.pauseTiming(); final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT) @@ -265,8 +324,8 @@ public class TextViewPrecomputedTextPerfTest { @Test public void testOnMeasure_PrecomputedText_Selectable() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH); - int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0); + int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST); + int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); while (state.keepRunning()) { state.pauseTiming(); final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT) @@ -289,8 +348,8 @@ public class TextViewPrecomputedTextPerfTest { @Test public void testOnDraw_RandomText() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH); - int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0); + int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST); + int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); @@ -299,8 +358,34 @@ public class TextViewPrecomputedTextPerfTest { textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED); textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL); textView.setText(text); + textView.measure(width, height); + textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight()); + final DisplayListCanvas c = node.start( + textView.getMeasuredWidth(), textView.getMeasuredHeight()); textView.nullLayouts(); - textView.onMeasure(width, height); + Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + textView.onDraw(c); + } + } + + @Test + public void testOnDraw_RandomText_Selectable() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST); + int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + final RenderNode node = RenderNode.create("benchmark", null); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final TestableTextView textView = new TestableTextView(getContext()); + textView.setTextIsSelectable(true); + textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED); + textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL); + textView.setText(text); + textView.measure(width, height); + textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight()); final DisplayListCanvas c = node.start( textView.getMeasuredWidth(), textView.getMeasuredHeight()); textView.nullLayouts(); @@ -314,8 +399,8 @@ public class TextViewPrecomputedTextPerfTest { @Test public void testOnDraw_PrecomputedText() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH); - int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0); + int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST); + int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); @@ -327,8 +412,8 @@ public class TextViewPrecomputedTextPerfTest { final TestableTextView textView = new TestableTextView(getContext()); textView.setTextMetricsParams(params); textView.setText(text); - textView.nullLayouts(); - textView.onMeasure(width, height); + textView.measure(width, height); + textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight()); final DisplayListCanvas c = node.start( textView.getMeasuredWidth(), textView.getMeasuredHeight()); textView.nullLayouts(); @@ -356,8 +441,8 @@ public class TextViewPrecomputedTextPerfTest { textView.setTextIsSelectable(true); textView.setTextMetricsParams(params); textView.setText(text); - textView.nullLayouts(); - textView.onMeasure(width, height); + textView.measure(width, height); + textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight()); final DisplayListCanvas c = node.start( textView.getMeasuredWidth(), textView.getMeasuredHeight()); textView.nullLayouts(); diff --git a/api/current.txt b/api/current.txt index 26fe641c59da..8321c1856607 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5196,6 +5196,7 @@ package android.app { field public static final java.lang.String CATEGORY_ERROR = "err"; field public static final java.lang.String CATEGORY_EVENT = "event"; field public static final java.lang.String CATEGORY_MESSAGE = "msg"; + field public static final java.lang.String CATEGORY_NAVIGATION = "navigation"; field public static final java.lang.String CATEGORY_PROGRESS = "progress"; field public static final java.lang.String CATEGORY_PROMO = "promo"; field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation"; @@ -7266,6 +7267,7 @@ package android.app.slice { public class SliceManager { method public android.app.slice.Slice bindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>); method public android.app.slice.Slice bindSlice(android.content.Intent, java.util.List<android.app.slice.SliceSpec>); + method public java.util.List<android.net.Uri> getPinnedSlices(); method public java.util.List<android.app.slice.SliceSpec> getPinnedSpecs(android.net.Uri); method public java.util.Collection<android.net.Uri> getSliceDescendants(android.net.Uri); method public android.net.Uri mapIntentToUri(android.content.Intent); @@ -7418,12 +7420,14 @@ package android.app.usage { method public int getEventType(); method public java.lang.String getPackageName(); method public java.lang.String getShortcutId(); + method public int getStandbyBucket(); method public long getTimeStamp(); field public static final int CONFIGURATION_CHANGE = 5; // 0x5 field public static final int MOVE_TO_BACKGROUND = 2; // 0x2 field public static final int MOVE_TO_FOREGROUND = 1; // 0x1 field public static final int NONE = 0; // 0x0 field public static final int SHORTCUT_INVOCATION = 8; // 0x8 + field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb field public static final int USER_INTERACTION = 7; // 0x7 } @@ -14436,6 +14440,7 @@ package android.graphics { method public static android.graphics.Typeface createFromFile(java.lang.String); method public static android.graphics.Typeface defaultFromStyle(int); method public int getStyle(); + method public int getWeight(); method public final boolean isBold(); method public final boolean isItalic(); field public static final int BOLD = 1; // 0x1 @@ -16434,8 +16439,8 @@ package android.hardware.camera2.params { } public final class SessionConfiguration { - ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.StateCallback); - method public java.util.concurrent.Executor getExecutor(); + ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler); + method public android.os.Handler getHandler(); method public android.hardware.camera2.params.InputConfiguration getInputConfiguration(); method public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations(); method public android.hardware.camera2.CaptureRequest getSessionParameters(); @@ -21244,9 +21249,10 @@ package android.inputmethodservice { method public final boolean switchToPreviousInputMethod(); method public void updateFullscreenMode(); method public void updateInputViewShown(); + field public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3; // 0x3 field public static final int BACK_DISPOSITION_DEFAULT = 0; // 0x0 - field public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // 0x2 - field public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // 0x1 + field public static final deprecated int BACK_DISPOSITION_WILL_DISMISS = 2; // 0x2 + field public static final deprecated int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // 0x1 } public class InputMethodService.InputMethodImpl extends android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl { @@ -28676,7 +28682,7 @@ package android.net.wifi { field public static final int IEEE8021X = 3; // 0x3 field public static final int NONE = 0; // 0x0 field public static final int WPA_EAP = 2; // 0x2 - field public static final deprecated int WPA_PSK = 1; // 0x1 + field public static final int WPA_PSK = 1; // 0x1 field public static final java.lang.String[] strings; field public static final java.lang.String varName = "key_mgmt"; } diff --git a/api/system-current.txt b/api/system-current.txt index 43425cb2da83..af783caf7c12 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -261,6 +261,7 @@ package android.app { public class AppOpsManager { method public static java.lang.String[] getOpStrs(); + method public void setMode(java.lang.String, int, java.lang.String, int); method public void setUidMode(java.lang.String, int, int); field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover"; field public static final java.lang.String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications"; @@ -335,6 +336,9 @@ package android.app { } public class Notification implements android.os.Parcelable { + field public static final java.lang.String CATEGORY_CAR_EMERGENCY = "car_emergency"; + field public static final java.lang.String CATEGORY_CAR_INFORMATION = "car_information"; + field public static final java.lang.String CATEGORY_CAR_WARNING = "car_warning"; field public static final java.lang.String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup"; field public static final java.lang.String EXTRA_SUBSTITUTE_APP_NAME = "android.substName"; field public static final int FLAG_AUTOGROUP_SUMMARY = 1024; // 0x400 @@ -718,10 +722,8 @@ package android.app.usage { public static final class UsageEvents.Event { method public java.lang.String getNotificationChannelId(); - method public int getStandbyBucket(); field public static final int NOTIFICATION_INTERRUPTION = 12; // 0xc field public static final int NOTIFICATION_SEEN = 10; // 0xa - field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb } public final class UsageStatsManager { @@ -5261,12 +5263,13 @@ package android.telephony { } public class UiccSlotInfo implements android.os.Parcelable { - ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int); + ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int, boolean); method public int describeContents(); method public java.lang.String getCardId(); method public int getCardStateInfo(); method public boolean getIsActive(); method public boolean getIsEuicc(); + method public boolean getIsExtendedApduSupported(); method public int getLogicalSlotIdx(); method public void writeToParcel(android.os.Parcel, int); field public static final int CARD_STATE_INFO_ABSENT = 1; // 0x1 @@ -6127,19 +6130,24 @@ package android.telephony.ims.stub { } public final class ImsFeatureConfiguration implements android.os.Parcelable { - ctor public ImsFeatureConfiguration(); method public int describeContents(); - method public int[] getServiceFeatures(); + method public java.util.Set<android.telephony.ims.stub.ImsFeatureConfiguration.FeatureSlotPair> getServiceFeatures(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.telephony.ims.stub.ImsFeatureConfiguration> CREATOR; } public static class ImsFeatureConfiguration.Builder { ctor public ImsFeatureConfiguration.Builder(); - method public android.telephony.ims.stub.ImsFeatureConfiguration.Builder addFeature(int); + method public android.telephony.ims.stub.ImsFeatureConfiguration.Builder addFeature(int, int); method public android.telephony.ims.stub.ImsFeatureConfiguration build(); } + public static final class ImsFeatureConfiguration.FeatureSlotPair { + ctor public ImsFeatureConfiguration.FeatureSlotPair(int, int); + field public final int featureType; + field public final int slotId; + } + public class ImsMultiEndpointImplBase { ctor public ImsMultiEndpointImplBase(); method public final void onImsExternalCallStateUpdate(java.util.List<android.telephony.ims.ImsExternalCallState>); diff --git a/api/test-current.txt b/api/test-current.txt index 9d67f4c3bb60..54ddd5de7969 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1,3 +1,12 @@ +package android { + + public static final class Manifest.permission { + field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE"; + field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"; + } + +} + package android.animation { public class ValueAnimator extends android.animation.Animator { diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 7f0a26c1714e..50a5ddda4840 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -82,10 +82,8 @@ statsd_common_static_libraries := \ statsd_common_shared_libraries := \ libbase \ libbinder \ - libcutils \ libincident \ liblog \ - libselinux \ libutils \ libservices \ libprotoutil \ @@ -198,7 +196,7 @@ LOCAL_SRC_FILES := \ tests/e2e/WakelockDuration_e2e_test.cpp \ tests/e2e/MetricConditionLink_e2e_test.cpp \ tests/e2e/Attribution_e2e_test.cpp \ - tests/e2e/GaugeMetric_e2e_test.cpp \ + tests/e2e/GaugeMetric_e2e_push_test.cpp \ tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp \ tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp \ tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp @@ -308,4 +306,4 @@ statsd_common_static_libraries:= statsd_common_shared_libraries:= -include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/cmds/statsd/benchmark/filter_value_benchmark.cpp b/cmds/statsd/benchmark/filter_value_benchmark.cpp index 66c4defe7adb..cfe477d7ca8f 100644 --- a/cmds/statsd/benchmark/filter_value_benchmark.cpp +++ b/cmds/statsd/benchmark/filter_value_benchmark.cpp @@ -54,28 +54,12 @@ static void BM_FilterValue(benchmark::State& state) { translateFieldMatcher(field_matcher, &matchers); while (state.KeepRunning()) { - vector<HashableDimensionKey> output; - filterValues(matchers, event.getValues(), &output); - } -} - -BENCHMARK(BM_FilterValue); - -static void BM_FilterValue2(benchmark::State& state) { - LogEvent event(1, 100000); - FieldMatcher field_matcher; - createLogEventAndMatcher(&event, &field_matcher); - - std::vector<Matcher> matchers; - translateFieldMatcher(field_matcher, &matchers); - - while (state.KeepRunning()) { HashableDimensionKey output; filterValues(matchers, event.getValues(), &output); } } -BENCHMARK(BM_FilterValue2); +BENCHMARK(BM_FilterValue); } // namespace statsd } // namespace os diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp index 0c9b7016eaff..dfd8705f83aa 100644 --- a/cmds/statsd/src/FieldValue.cpp +++ b/cmds/statsd/src/FieldValue.cpp @@ -48,6 +48,11 @@ bool Field::matches(const Matcher& matcher) const { return true; } + if (matcher.hasAllPositionMatcher() && + (mField & (matcher.mMask & kClearAllPositionMatcherMask)) == matcher.mMatcher.getField()) { + return true; + } + return false; } @@ -67,6 +72,10 @@ void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int* return; } switch (matcher.position()) { + case Position::ALL: + pos[depth] = 0x00; + mask[depth] = 0x7f; + break; case Position::ANY: pos[depth] = 0; mask[depth] = 0; diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h index 0e3ae06033e7..f7ce23b04339 100644 --- a/cmds/statsd/src/FieldValue.h +++ b/cmds/statsd/src/FieldValue.h @@ -30,6 +30,7 @@ const int32_t kAttributionField = 1; const int32_t kMaxLogDepth = 2; const int32_t kLastBitMask = 0x80; const int32_t kClearLastBitDeco = 0x7f; +const int32_t kClearAllPositionMatcherMask = 0xffff00ff; enum Type { UNKNOWN, INT, LONG, FLOAT, STRING }; @@ -205,6 +206,7 @@ public: * First: [Matcher Field] 0x02010101 [Mask]0xff7f7f7f * Last: [Matcher Field] 0x02018001 [Mask]0xff7f807f * Any: [Matcher Field] 0x02010001 [Mask]0xff7f007f + * All: [Matcher Field] 0x02010001 [Mask]0xff7f7f7f * * [To match a log Field with a Matcher] we apply the bit mask to the log Field and check if * the result is equal to the Matcher Field. That's a bit wise AND operation + check if 2 ints are @@ -226,9 +228,21 @@ struct Matcher { return mMask; } + inline int32_t getRawMaskAtDepth(int32_t depth) const { + int32_t field = (mMask & 0x00ffffff); + int32_t shift = 8 * (kMaxLogDepth - depth); + int32_t mask = 0xff << shift; + + return (field & mask) >> shift; + } + + bool hasAllPositionMatcher() const { + return mMatcher.getDepth() == 2 && getRawMaskAtDepth(1) == 0x7f; + } + bool hasAnyPositionMatcher(int* prefix) const { - if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(2) == 0) { - (*prefix) = mMatcher.getPrefix(2); + if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(1) == 0) { + (*prefix) = mMatcher.getPrefix(1); return true; } return false; diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp index d0c83119dc43..71030345b0aa 100644 --- a/cmds/statsd/src/HashableDimensionKey.cpp +++ b/cmds/statsd/src/HashableDimensionKey.cpp @@ -61,125 +61,22 @@ android::hash_t hashDimension(const HashableDimensionKey& value) { bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values, HashableDimensionKey* output) { - for (size_t i = 0; i < matcherFields.size(); ++i) { - const auto& matcher = matcherFields[i]; - bool found = false; - for (const auto& value : values) { + size_t num_matches = 0; + for (const auto& value : values) { + for (size_t i = 0; i < matcherFields.size(); ++i) { + const auto& matcher = matcherFields[i]; // TODO: potential optimization here to break early because all fields are naturally // sorted. if (value.mField.matches(matcher)) { output->addValue(value); - output->mutableValue(i)->mField.setTag(value.mField.getTag()); - output->mutableValue(i)->mField.setField(value.mField.getField() & matcher.mMask); - found = true; - break; - } - } - - if (!found) { - VLOG("We can't find a dimension value for matcher (%d)%#x.", matcher.mMatcher.getTag(), - matcher.mMatcher.getField()); - return false; - } - } - - return true; -} - -// Filter fields using the matchers and output the results as a HashableDimensionKey. -// Note: HashableDimensionKey is just a wrapper for vector<FieldValue> -bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values, - vector<HashableDimensionKey>* output) { - output->push_back(HashableDimensionKey()); - // Top level is only tag id. Now take the real child matchers - int prevAnyMatcherPrefix = 0; - size_t prevPrevFanout = 0; - size_t prevFanout = 0; - - // For each matcher get matched results. - vector<FieldValue> matchedResults(2); - for (const auto& matcher : matcherFields) { - size_t num_matches = 0; - for (const auto& value : values) { - // TODO: potential optimization here to break early because all fields are naturally - // sorted. - if (value.mField.matches(matcher)) { - if (num_matches >= matchedResults.size()) { - matchedResults.resize(num_matches * 2); - } - matchedResults[num_matches].mField.setTag(value.mField.getTag()); - matchedResults[num_matches].mField.setField(value.mField.getField() & matcher.mMask); - matchedResults[num_matches].mValue = value.mValue; + output->mutableValue(num_matches)->mField.setTag(value.mField.getTag()); + output->mutableValue(num_matches)->mField.setField( + value.mField.getField() & matcher.mMask); num_matches++; } } - - if (num_matches == 0) { - VLOG("We can't find a dimension value for matcher (%d)%#x.", matcher.mMatcher.getTag(), - matcher.mMatcher.getField()); - continue; - } - - if (num_matches == 1) { - for (auto& dimension : *output) { - dimension.addValue(matchedResults[0]); - } - prevAnyMatcherPrefix = 0; - prevFanout = 0; - continue; - } - - // All the complexity below is because we support ANY in dimension. - bool createFanout = true; - // createFanout is true when the matcher doesn't need to follow the prev matcher's - // order. - // e.g., get (uid, tag) from any position in attribution. because we have translated - // it as 2 matchers, they need to follow the same ordering, we can't create a cross - // product of all uid and tags. - // However, if the 2 matchers have different prefix, they will create a cross product - // e.g., [any uid] [any some other repeated field], we will create a cross product for them - if (prevAnyMatcherPrefix != 0) { - int anyMatcherPrefix = 0; - bool isAnyMatcher = matcher.hasAnyPositionMatcher(&anyMatcherPrefix); - if (isAnyMatcher && anyMatcherPrefix == prevAnyMatcherPrefix) { - createFanout = false; - } else { - prevAnyMatcherPrefix = anyMatcherPrefix; - } - } - - // Each matcher should match exact one field, unless position is ANY - // When x number of fields matches a matcher, the returned dimension - // size is multiplied by x. - int oldSize; - if (createFanout) { - // First create fanout (fanout size is matchedResults.Size which could be one, - // which means we do nothing here) - oldSize = output->size(); - for (size_t i = 1; i < num_matches; i++) { - output->insert(output->end(), output->begin(), output->begin() + oldSize); - } - prevPrevFanout = oldSize; - prevFanout = num_matches; - } else { - // If we should not create fanout, e.g., uid tag from same position should be remain - // together. - oldSize = prevPrevFanout; - if (prevFanout != num_matches) { - // sanity check. - ALOGE("2 Any matcher result in different output"); - return false; - } - } - // now add the matched field value to output - for (size_t i = 0; i < num_matches; i++) { - for (int j = 0; j < oldSize; j++) { - (*output)[i * oldSize + j].addValue(matchedResults[i]); - } - } } - - return output->size() > 0 && (*output)[0].getValues().size() > 0; + return num_matches > 0; } void filterGaugeValues(const std::vector<Matcher>& matcherFields, diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h index 4cfed883ec07..6f4941f717ee 100644 --- a/cmds/statsd/src/HashableDimensionKey.h +++ b/cmds/statsd/src/HashableDimensionKey.h @@ -122,17 +122,14 @@ android::hash_t hashDimension(const HashableDimensionKey& key); /** * Creating HashableDimensionKeys from FieldValues using matcher. * - * This function may make modifications to the Field if the matcher has Position=LAST or ANY in - * it. This is because: for example, when we create dimension from last uid in attribution chain, + * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL + * in it. This is because: for example, when we create dimension from last uid in attribution chain, * In one event, uid 1000 is at position 5 and it's the last * In another event, uid 1000 is at position 6, and it's the last * these 2 events should be mapped to the same dimension. So we will remove the original position * from the dimension key for the uid field (by applying 0x80 bit mask). */ bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values, - std::vector<HashableDimensionKey>* output); -// This function is used when there is at most one output dimension key. (no ANY matcher) -bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values, HashableDimensionKey* output); /** diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 02d4dc985e84..8f72a8f0958c 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -62,6 +62,9 @@ const int FIELD_ID_ID = 2; const int FIELD_ID_UID_MAP = 2; const int FIELD_ID_LAST_REPORT_ELAPSED_NANOS = 3; const int FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS = 4; +const int FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS = 5; +const int FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS = 6; + #define STATS_DATA_DIR "/data/misc/stats-data" @@ -260,6 +263,8 @@ void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS); int64_t lastReportTimeNs = it->second->getLastReportTimeNs(); + int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs(); + // First, fill in ConfigMetricsReport using current data on memory, which // starts from filling in StatsLogReport's. it->second->onDumpReport(dumpTimeStampNs, &proto); @@ -276,6 +281,10 @@ void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t (long long)lastReportTimeNs); proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS, (long long)dumpTimeStampNs); + proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS, + (long long)lastReportWallClockNs); + proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS, + (long long)getWallClockNs()); // End of ConfigMetricsReport (reports). proto.end(reportsToken); diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 8db82006d082..8b42146c6621 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -121,7 +121,8 @@ private: FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3); FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1); FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2); - FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice); + FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid); + FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain); FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent); FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition); FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition); @@ -138,6 +139,7 @@ private: FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition); FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition); + }; } // namespace statsd diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 8ba35b76435f..298f49457f38 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -110,6 +110,11 @@ message Atom { BluetoothEnabledStateChanged bluetooth_enabled_state_changed = 67; BluetoothConnectionStateChanged bluetooth_connection_state_changed = 68; BluetoothA2dpAudioStateChanged bluetooth_a2dp_audio_state_changed = 69; + UsbConnectorStateChanged usb_connector_changed = 70; + SpeakerImpedanceReported speaker_impedance_reported = 71; + HardwareFailed hardware_failed = 72; + PhysicalDropDetected physical_drop_detected = 73; + ChargeCyclesReported charge_cycles_reported = 74; // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15. } @@ -965,6 +970,108 @@ message BluetoothA2dpAudioStateChanged { } /** + * Logs when something is plugged into or removed from the USB-C connector. + * + * Logged from: + * Vendor USB HAL. + */ +message UsbConnectorStateChanged { + enum State { + DISCONNECTED = 0; + CONNECTED = 1; + } + optional State state = 1; +} + +/** + * Logs the reported speaker impedance. + * + * Logged from: + * Vendor audio implementation. + */ +message SpeakerImpedanceReported { + optional int32 speaker_location = 1; + optional int32 impedance = 2; +} + +/** + * Logs the report of a failed hardware. + * + * Logged from: + * Vendor HALs. + * + */ +message HardwareFailed { + enum HardwareType { + HARDWARE_FAILED_UNKNOWN = 0; + HARDWARE_FAILED_MICROPHONE = 1; + HARDWARE_FAILED_CODEC = 2; + HARDWARE_FAILED_SPEAKER = 3; + HARDWARE_FAILED_FINGERPRINT = 4; + } + optional HardwareType hardware_type = 1; + + /* hardware_location allows vendors to differentiate between multiple instances of + * the same hardware_type. The specific locations are vendor defined integers, + * referring to board-specific numbering schemes. + */ + optional int32 hardware_location = 2; + + /* failure_code is specific to the HardwareType of the failed hardware. + * It should use the enum values defined below. + */ + enum MicrophoneFailureCode { + MICROPHONE_FAILURE_COMPLETE = 0; + } + enum CodecFailureCode { + CODEC_FAILURE_COMPLETE = 0; + } + enum SpeakerFailureCode { + SPEAKER_FAILURE_COMPLETE = 0; + SPEAKER_FAILURE_HIGH_Z = 1; + SPEAKER_FAILURE_SHORT = 2; + } + enum FingerprintFailureCode { + FINGERPRINT_FAILURE_COMPLETE = 0; + FINGERPRINT_SENSOR_BROKEN = 1; + FINGERPRINT_TOO_MANY_DEAD_PIXELS = 2; + } + optional int32 failure_code = 3; +} + +/** + * Log an event when the device has been physically dropped. + * Reported from the /vendor partition. + */ +message PhysicalDropDetected { + // Confidence that the event was actually a drop, 0 -> 100 + optional int32 confidence_pctg = 1; + // Peak acceleration of the drop, in 1/1000s of a g. + optional int32 accel_peak_thousandths_g = 2; +} + +/** + * Log bucketed battery charge cycles. + * + * Each bucket represents cycles of the battery past + * a given charge point. For example, bucket 1 is the + * lowest 1/8th of the battery, and bucket 8 is 100%. + * + * Logged from: + * /sys/class/power_supply/bms/cycle_count, via Vendor. + */ +message ChargeCyclesReported { + optional int32 cycle_bucket_1 = 1; + optional int32 cycle_bucket_2 = 2; + optional int32 cycle_bucket_3 = 3; + optional int32 cycle_bucket_4 = 4; + optional int32 cycle_bucket_5 = 5; + optional int32 cycle_bucket_6 = 6; + optional int32 cycle_bucket_7 = 7; + optional int32 cycle_bucket_8 = 8; +} + +/** * Logs the duration of a davey (jank of >=700ms) when it occurs * * Logged from: diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp index 4913aef3347f..73efb39ac119 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp +++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp @@ -327,25 +327,7 @@ void SimpleConditionTracker::evaluateCondition( // have both sliced and unsliced version of a predicate. handleConditionEvent(outputValue, matchedState == 1, &overallState, &overallChanged); } else { - std::vector<HashableDimensionKey> outputValues; - filterValues(mOutputDimensions, event.getValues(), &outputValues); - - // If this event has multiple nodes in the attribution chain, this log event probably will - // generate multiple dimensions. If so, we will find if the condition changes for any - // dimension and ask the corresponding metric producer to verify whether the actual sliced - // condition has changed or not. - // A high level assumption is that a predicate is either sliced or unsliced. We will never - // have both sliced and unsliced version of a predicate. - for (const HashableDimensionKey& outputValue : outputValues) { - ConditionState tempState; - bool tempChanged = false; - handleConditionEvent(outputValue, matchedState == 1, &tempState, &tempChanged); - if (tempChanged) { - overallChanged = true; - } - // ConditionState's | operator is overridden - overallState = overallState | tempState; - } + ALOGE("The condition tracker should not be sliced by ANY position matcher."); } conditionCache[mIndex] = overallState; conditionChangedCache[mIndex] = overallChanged; diff --git a/cmds/statsd/src/condition/StateTracker.cpp b/cmds/statsd/src/condition/StateTracker.cpp index c68875c58162..fe1740b24dd4 100644 --- a/cmds/statsd/src/condition/StateTracker.cpp +++ b/cmds/statsd/src/condition/StateTracker.cpp @@ -137,21 +137,18 @@ void StateTracker::evaluateCondition(const LogEvent& event, VLOG("StateTracker evaluate event %s", event.ToString().c_str()); - vector<HashableDimensionKey> keys; - vector<HashableDimensionKey> outputs; - filterValues(mPrimaryKeys, event.getValues(), &keys); - filterValues(mOutputDimensions, event.getValues(), &outputs); - if (keys.size() != 1 || outputs.size() != 1) { - ALOGE("More than 1 states in the event?? panic now!"); + // Primary key can exclusive fields must be simple fields. so there won't be more than + // one keys matched. + HashableDimensionKey primaryKey; + HashableDimensionKey state; + if (!filterValues(mPrimaryKeys, event.getValues(), &primaryKey) || + !filterValues(mOutputDimensions, event.getValues(), &state)) { + ALOGE("Failed to filter fields in the event?? panic now!"); conditionCache[mIndex] = mSlicedState.size() > 0 ? ConditionState::kTrue : ConditionState::kFalse; conditionChangedCache[mIndex] = false; return; } - // Primary key can exclusive fields must be simple fields. so there won't be more than - // one keys matched. - const auto& primaryKey = keys[0]; - const auto& state = outputs[0]; hitGuardRail(primaryKey); VLOG("StateTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str()); diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp index d0f55abe7033..f5310a419c92 100644 --- a/cmds/statsd/src/config/ConfigManager.cpp +++ b/cmds/statsd/src/config/ConfigManager.cpp @@ -68,12 +68,25 @@ void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& confi { lock_guard <mutex> lock(mMutex); + auto it = mConfigs.find(key); + + const int numBytes = config.ByteSize(); + vector<uint8_t> buffer(numBytes); + config.SerializeToArray(&buffer[0], numBytes); + + const bool isDuplicate = + it != mConfigs.end() && + StorageManager::hasIdenticalConfig(key, buffer); + + // Update saved file on disk. We still update timestamp of file when + // there exists a duplicate configuration to avoid garbage collection. + update_saved_configs_locked(key, buffer, numBytes); + + if (isDuplicate) return; + // Add to set mConfigs.insert(key); - // Save to disk - update_saved_configs_locked(key, config); - for (sp<ConfigListener> listener : mListeners) { broadcastList.push_back(listener); } @@ -137,7 +150,6 @@ void ConfigManager::RemoveConfigs(int uid) { { lock_guard <mutex> lock(mMutex); - for (auto it = mConfigs.begin(); it != mConfigs.end();) { // Remove from map if (it->GetUid() == uid) { @@ -230,16 +242,16 @@ void ConfigManager::Dump(FILE* out) { } } -void ConfigManager::update_saved_configs_locked(const ConfigKey& key, const StatsdConfig& config) { +void ConfigManager::update_saved_configs_locked(const ConfigKey& key, + const vector<uint8_t>& buffer, + const int numBytes) { // If there is a pre-existing config with same key we should first delete it. remove_saved_configs(key); // Then we save the latest config. - string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_SERVICE_DIR, time(nullptr), - key.GetUid(), (long long)key.GetId()); - const int numBytes = config.ByteSize(); - vector<uint8_t> buffer(numBytes); - config.SerializeToArray(&buffer[0], numBytes); + string file_name = + StringPrintf("%s/%ld_%d_%lld", STATS_SERVICE_DIR, time(nullptr), + key.GetUid(), (long long)key.GetId()); StorageManager::writeFile(file_name.c_str(), &buffer[0], numBytes); } diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h index a0c1c1cb16f8..9a38188a120c 100644 --- a/cmds/statsd/src/config/ConfigManager.h +++ b/cmds/statsd/src/config/ConfigManager.h @@ -115,7 +115,9 @@ private: /** * Save the configs to disk. */ - void update_saved_configs_locked(const ConfigKey& key, const StatsdConfig& config); + void update_saved_configs_locked(const ConfigKey& key, + const std::vector<uint8_t>& buffer, + const int numBytes); /** * Remove saved configs from disk. @@ -123,7 +125,7 @@ private: void remove_saved_configs(const ConfigKey& key); /** - * The Configs that have been set. Each config should + * Config keys that have been set. */ std::set<ConfigKey> mConfigs; diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index c6c4d135ad3f..7a55f6065e88 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -21,6 +21,7 @@ #include <android/util/ProtoOutputStream.h> #include "../stats_log_util.h" #include "statslog.h" +#include "storage/StorageManager.h" namespace android { namespace os { @@ -403,6 +404,8 @@ void StatsdStats::dumpStats(FILE* out) const { fprintf(out, "alert %lld declared %d times\n", (long long)stats.first, stats.second); } } + fprintf(out, "********Disk Usage stats***********\n"); + StorageManager::printStats(out); fprintf(out, "********Pushed Atom stats***********\n"); const size_t atomCounts = mPushedAtomStats.size(); for (size_t i = 2; i < atomCounts; i++) { diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp index 364d4e9d5c94..b7105b351a10 100644 --- a/cmds/statsd/src/matchers/matcher_util.cpp +++ b/cmds/statsd/src/matchers/matcher_util.cpp @@ -185,6 +185,9 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, ranges.push_back(std::make_pair(newStart, end)); break; } + case Position::ALL: + ALOGE("Not supported: field matcher with ALL position."); + break; case Position::POSITION_UNKNOWN: break; } diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp index 22b2a30af328..8e8a529bfff1 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.cpp +++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp @@ -99,6 +99,24 @@ CountMetricProducer::~CountMetricProducer() { VLOG("~CountMetricProducer() called"); } +void CountMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { + if (mCurrentSlicedCounter == nullptr || + mCurrentSlicedCounter->size() == 0) { + return; + } + + fprintf(out, "CountMetric %lld dimension size %lu\n", (long long)mMetricId, + (unsigned long)mCurrentSlicedCounter->size()); + if (verbose) { + for (const auto& it : *mCurrentSlicedCounter) { + fprintf(out, "\t(what)%s\t(condition)%s %lld\n", + it.first.getDimensionKeyInWhat().toString().c_str(), + it.first.getDimensionKeyInCondition().toString().c_str(), + (unsigned long long)it.second); + } + } +} + void CountMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) { VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId); } @@ -249,7 +267,6 @@ void CountMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) } else { info.mBucketEndNs = fullBucketEndTimeNs; } - info.mBucketNum = mCurrentBucketNum; for (const auto& counter : *mCurrentSlicedCounter) { info.mCount = counter.second; auto& bucketList = mPastBuckets[counter.first]; diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h index 1d8e42be635c..ef738acd5772 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.h +++ b/cmds/statsd/src/metrics/CountMetricProducer.h @@ -36,7 +36,6 @@ struct CountBucket { int64_t mBucketStartNs; int64_t mBucketEndNs; int64_t mCount; - uint64_t mBucketNum; }; class CountMetricProducer : public MetricProducer { @@ -67,7 +66,7 @@ private: // Internal function to calculate the current used bytes. size_t byteSizeLocked() const override; - void dumpStatesLocked(FILE* out, bool verbose) const override{}; + void dumpStatesLocked(FILE* out, bool verbose) const override; void dropDataLocked(const uint64_t dropTimeNs) override; diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index bc09683d79ad..c6b9405e424d 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -88,6 +88,12 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat translateFieldMatcher(internalDimensions, &mInternalDimensions); mContainANYPositionInInternalDimensions = HasPositionANY(internalDimensions); } + if (mContainANYPositionInInternalDimensions) { + ALOGE("Position ANY in internal dimension not supported."); + } + if (mContainANYPositionInDimensionsInWhat) { + ALOGE("Position ANY in dimension_in_what not supported."); + } if (metric.has_dimensions_in_condition()) { translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition); @@ -589,18 +595,10 @@ void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey it->second->noteStart(DEFAULT_DIMENSION_KEY, condition, event.GetElapsedTimestampNs(), conditionKeys); } else { - if (mContainANYPositionInInternalDimensions) { - std::vector<HashableDimensionKey> dimensionKeys; - filterValues(mInternalDimensions, event.getValues(), &dimensionKeys); - for (const auto& key : dimensionKeys) { - it->second->noteStart(key, condition, event.GetElapsedTimestampNs(), conditionKeys); - } - } else { - HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY; - filterValues(mInternalDimensions, event.getValues(), &dimensionKey); - it->second->noteStart( - dimensionKey, condition, event.GetElapsedTimestampNs(), conditionKeys); - } + HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY; + filterValues(mInternalDimensions, event.getValues(), &dimensionKey); + it->second->noteStart( + dimensionKey, condition, event.GetElapsedTimestampNs(), conditionKeys); } } @@ -612,8 +610,8 @@ void DurationMetricProducer::onMatchedLogEventInternalLocked( ALOGW("Not used in duration tracker."); } -void DurationMetricProducer::onMatchedLogEventLocked_simple(const size_t matcherIndex, - const LogEvent& event) { +void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, + const LogEvent& event) { uint64_t eventTimeNs = event.GetElapsedTimestampNs(); if (eventTimeNs < mStartTimeNs) { return; @@ -712,117 +710,6 @@ void DurationMetricProducer::onMatchedLogEventLocked_simple(const size_t matcher } } -void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, - const LogEvent& event) { - if (!mContainANYPositionInDimensionsInWhat) { - onMatchedLogEventLocked_simple(matcherIndex, event); - return; - } - - uint64_t eventTimeNs = event.GetElapsedTimestampNs(); - if (eventTimeNs < mStartTimeNs) { - return; - } - - flushIfNeededLocked(event.GetElapsedTimestampNs()); - - // Handles Stopall events. - if (matcherIndex == mStopAllIndex) { - for (auto& whatIt : mCurrentSlicedDurationTrackerMap) { - for (auto& pair : whatIt.second) { - pair.second->noteStopAll(event.GetElapsedTimestampNs()); - } - } - return; - } - - vector<HashableDimensionKey> dimensionInWhatValues; - if (!mDimensionsInWhat.empty()) { - filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues); - } else { - dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY); - } - - // Handles Stop events. - if (matcherIndex == mStopIndex) { - if (mUseWhatDimensionAsInternalDimension) { - for (const HashableDimensionKey& whatKey : dimensionInWhatValues) { - auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey); - if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { - for (const auto& condIt : whatIt->second) { - condIt.second->noteStop(whatKey, event.GetElapsedTimestampNs(), false); - } - } - } - return; - } - - HashableDimensionKey internalDimensionKey = DEFAULT_DIMENSION_KEY; - if (!mInternalDimensions.empty()) { - filterValues(mInternalDimensions, event.getValues(), &internalDimensionKey); - } - - for (const HashableDimensionKey& whatDimension : dimensionInWhatValues) { - auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension); - if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { - for (const auto& condIt : whatIt->second) { - condIt.second->noteStop( - internalDimensionKey, event.GetElapsedTimestampNs(), false); - } - } - } - return; - } - - bool condition; - ConditionKey conditionKey; - std::unordered_set<HashableDimensionKey> dimensionKeysInCondition; - if (mConditionSliced) { - for (const auto& link : mMetric2ConditionLinks) { - getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]); - } - - auto conditionState = - mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition, - !mSameConditionDimensionsInTracker, - !mHasLinksToAllConditionDimensionsInTracker, - &dimensionKeysInCondition); - condition = (conditionState == ConditionState::kTrue); - if (mDimensionsInCondition.empty() && condition) { - dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY); - } - } else { - condition = mCondition; - if (condition) { - dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY); - } - } - - for (const auto& whatDimension : dimensionInWhatValues) { - if (dimensionKeysInCondition.empty()) { - handleStartEvent(MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY), - conditionKey, condition, event); - } else { - auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension); - // If the what dimension is already there, we should update all the trackers even - // the condition is false. - if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { - for (const auto& condIt : whatIt->second) { - const bool cond = dimensionKeysInCondition.find(condIt.first) != - dimensionKeysInCondition.end(); - handleStartEvent(MetricDimensionKey(whatDimension, condIt.first), - conditionKey, cond, event); - dimensionKeysInCondition.erase(condIt.first); - } - } - for (const auto& conditionDimension : dimensionKeysInCondition) { - handleStartEvent(MetricDimensionKey(whatDimension, conditionDimension), - conditionKey, condition, event); - } - } - } -} - size_t DurationMetricProducer::byteSizeLocked() const { size_t totalSize = 0; for (const auto& pair : mPastBuckets) { diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index 6746e116333f..985749df63dd 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -52,8 +52,6 @@ public: protected: void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override; - void onMatchedLogEventLocked_simple(const size_t matcherIndex, const LogEvent& event); - void onMatchedLogEventInternalLocked( const size_t matcherIndex, const MetricDimensionKey& eventKey, const ConditionKey& conditionKeys, bool condition, diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index e479e5caec2f..55a281ed61a0 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -56,6 +56,7 @@ const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1; const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2; const int FIELD_ID_ATOM = 3; const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4; +const int FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP = 5; GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric, const int conditionIndex, @@ -126,6 +127,24 @@ GaugeMetricProducer::~GaugeMetricProducer() { } } +void GaugeMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { + if (mCurrentSlicedBucket == nullptr || + mCurrentSlicedBucket->size() == 0) { + return; + } + + fprintf(out, "GaugeMetric %lld dimension size %lu\n", (long long)mMetricId, + (unsigned long)mCurrentSlicedBucket->size()); + if (verbose) { + for (const auto& it : *mCurrentSlicedBucket) { + fprintf(out, "\t(what)%s\t(condition)%s %d atoms\n", + it.first.getDimensionKeyInWhat().toString().c_str(), + it.first.getDimensionKeyInCondition().toString().c_str(), + (int)it.second.size()); + } + } +} + void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, ProtoOutputStream* protoOutput) { VLOG("gauge metric %lld report now...", (long long)mMetricId); @@ -168,21 +187,28 @@ void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, (long long)bucket.mBucketEndNs); if (!bucket.mGaugeAtoms.empty()) { - uint64_t atomsToken = - protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_ATOM); for (const auto& atom : bucket.mGaugeAtoms) { + uint64_t atomsToken = + protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | + FIELD_ID_ATOM); writeFieldValueTreeToStream(mTagId, *(atom.mFields), protoOutput); + protoOutput->end(atomsToken); } - protoOutput->end(atomsToken); + const bool truncateTimestamp = + android::util::kNotTruncatingTimestampAtomWhiteList.find(mTagId) == + android::util::kNotTruncatingTimestampAtomWhiteList.end(); + const int64_t wall_clock_ns = truncateTimestamp ? + truncateTimestampNsToFiveMinutes(getWallClockNs()) : getWallClockNs(); for (const auto& atom : bucket.mGaugeAtoms) { - const bool truncateTimestamp = - android::util::kNotTruncatingTimestampAtomWhiteList.find(mTagId) == - android::util::kNotTruncatingTimestampAtomWhiteList.end(); int64_t timestampNs = truncateTimestamp ? truncateTimestampNsToFiveMinutes(atom.mTimestamps) : atom.mTimestamps; protoOutput->write( FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ELAPSED_ATOM_TIMESTAMP, (long long)timestampNs); + protoOutput->write( + FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | + FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP, + (long long)wall_clock_ns); } } protoOutput->end(bucketInfoToken); @@ -393,7 +419,6 @@ void GaugeMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) } else { info.mBucketEndNs = fullBucketEndTimeNs; } - info.mBucketNum = mCurrentBucketNum; for (const auto& slice : *mCurrentSlicedBucket) { info.mGaugeAtoms = slice.second; diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h index ca8dc7582680..dd6aff4130de 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.h +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h @@ -44,7 +44,6 @@ struct GaugeBucket { int64_t mBucketStartNs; int64_t mBucketEndNs; std::vector<GaugeAtom> mGaugeAtoms; - uint64_t mBucketNum; }; typedef std::unordered_map<MetricDimensionKey, std::vector<GaugeAtom>> @@ -106,7 +105,7 @@ private: // Internal function to calculate the current used bytes. size_t byteSizeLocked() const override; - void dumpStatesLocked(FILE* out, bool verbose) const override{}; + void dumpStatesLocked(FILE* out, bool verbose) const override; void dropDataLocked(const uint64_t dropTimeNs) override; diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp index 6c90b031a9cc..f4495a19d700 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -53,39 +53,17 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY); } - if (mContainANYPositionInDimensionsInWhat) { - vector<HashableDimensionKey> dimensionInWhatValues; - if (!mDimensionsInWhat.empty()) { - filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues); - } else { - dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY); - } - - for (const auto& whatDimension : dimensionInWhatValues) { - for (const auto& conditionDimensionKey : dimensionKeysInCondition) { - onMatchedLogEventInternalLocked( - matcherIndex, MetricDimensionKey(whatDimension, conditionDimensionKey), - conditionKey, condition, event); - } - if (dimensionKeysInCondition.empty()) { - onMatchedLogEventInternalLocked( - matcherIndex, MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY), - conditionKey, condition, event); - } - } - } else { - HashableDimensionKey dimensionInWhat; - filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat); - MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY); - for (const auto& conditionDimensionKey : dimensionKeysInCondition) { - metricKey.setDimensionKeyInCondition(conditionDimensionKey); - onMatchedLogEventInternalLocked( - matcherIndex, metricKey, conditionKey, condition, event); - } - if (dimensionKeysInCondition.empty()) { - onMatchedLogEventInternalLocked( - matcherIndex, metricKey, conditionKey, condition, event); - } + HashableDimensionKey dimensionInWhat; + filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat); + MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY); + for (const auto& conditionDimensionKey : dimensionKeysInCondition) { + metricKey.setDimensionKeyInCondition(conditionDimensionKey); + onMatchedLogEventInternalLocked( + matcherIndex, metricKey, conditionKey, condition, event); + } + if (dimensionKeysInCondition.empty()) { + onMatchedLogEventInternalLocked( + matcherIndex, metricKey, conditionKey, condition, event); } } diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 1ca59a366fcb..6209bbe75812 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -53,7 +53,9 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap> &uidMap, const sp<AlarmMonitor>& anomalyAlarmMonitor, const sp<AlarmMonitor>& periodicAlarmMonitor) - : mConfigKey(key), mUidMap(uidMap), mLastReportTimeNs(timeBaseSec * NS_PER_SEC) { + : mConfigKey(key), mUidMap(uidMap), + mLastReportTimeNs(timeBaseSec * NS_PER_SEC), + mLastReportWallClockNs(getWallClockNs()) { mConfigValid = initStatsdConfig(key, config, *uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, mTagIds, mAllAtomMatchers, @@ -193,6 +195,7 @@ void MetricsManager::onDumpReport(const uint64_t dumpTimeStampNs, ProtoOutputStr } } mLastReportTimeNs = dumpTimeStampNs; + mLastReportWallClockNs = getWallClockNs(); VLOG("=========================Metric Reports End=========================="); } diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index dbab81431743..46a9b34c21a1 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -69,10 +69,14 @@ public: void dumpStates(FILE* out, bool verbose); // Returns the elapsed realtime when this metric manager last reported metrics. - uint64_t getLastReportTimeNs() { + inline int64_t getLastReportTimeNs() const { return mLastReportTimeNs; }; + inline int64_t getLastReportWallClockNs() const { + return mLastReportWallClockNs; + }; + virtual void dropData(const uint64_t dropTimeNs); // Config source owner can call onDumpReport() to get all the metrics collected. @@ -89,7 +93,8 @@ private: bool mConfigValid = false; - uint64_t mLastReportTimeNs; + int64_t mLastReportTimeNs; + int64_t mLastReportWallClockNs; // The uid log sources from StatsdConfig. std::vector<int32_t> mAllowedUid; @@ -158,7 +163,8 @@ private: FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions); FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks); - FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice); + FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid); + FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain); FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent); FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition); FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition); diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index 09913dc513fd..767260d26351 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -243,6 +243,23 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven } } +void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { + if (mCurrentSlicedBucket.size() == 0) { + return; + } + + fprintf(out, "ValueMetric %lld dimension size %lu\n", (long long)mMetricId, + (unsigned long)mCurrentSlicedBucket.size()); + if (verbose) { + for (const auto& it : mCurrentSlicedBucket) { + fprintf(out, "\t(what)%s\t(condition)%s (value)%lld\n", + it.first.getDimensionKeyInWhat().toString().c_str(), + it.first.getDimensionKeyInCondition().toString().c_str(), + (unsigned long long)it.second.sum); + } + } +} + bool ValueMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) { // ===========GuardRail============== // 1. Report the tuple count if the tuple count > soft limit @@ -355,7 +372,6 @@ void ValueMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) } else { info.mBucketEndNs = fullBucketEndTimeNs; } - info.mBucketNum = mCurrentBucketNum; int tainted = 0; for (const auto& slice : mCurrentSlicedBucket) { diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 5e42bd255df4..be57183bd926 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -34,7 +34,6 @@ struct ValueBucket { int64_t mBucketStartNs; int64_t mBucketEndNs; int64_t mValue; - uint64_t mBucketNum; }; class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver { @@ -99,7 +98,7 @@ private: // Internal function to calculate the current used bytes. size_t byteSizeLocked() const override; - void dumpStatesLocked(FILE* out, bool verbose) const override{}; + void dumpStatesLocked(FILE* out, bool verbose) const override; // Util function to flush the old packet. void flushIfNeededLocked(const uint64_t& eventTime) override; diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h index 7b3393fda7e6..bfb1ec7e06d6 100644 --- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h @@ -55,7 +55,6 @@ struct DurationBucket { uint64_t mBucketStartNs; uint64_t mBucketEndNs; uint64_t mDuration; - uint64_t mBucketNum; }; class DurationTracker { diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp index 8e0bf2678fea..058940d11b46 100644 --- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp @@ -219,7 +219,6 @@ bool MaxDurationTracker::flushCurrentBucket( DurationBucket info; info.mBucketStartNs = mCurrentBucketStartTimeNs; info.mBucketEndNs = currentBucketEndTimeNs; - info.mBucketNum = mCurrentBucketNum; info.mDuration = mDuration; (*output)[mEventKey].push_back(info); VLOG(" final duration for last bucket: %lld", (long long)mDuration); diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp index 2358415dfaf7..c8a5016c1db8 100644 --- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp @@ -165,13 +165,12 @@ bool OringDurationTracker::flushCurrentBucket( DurationBucket current_info; current_info.mBucketStartNs = mCurrentBucketStartTimeNs; current_info.mBucketEndNs = currentBucketEndTimeNs; - current_info.mBucketNum = mCurrentBucketNum; current_info.mDuration = mDuration; (*output)[mEventKey].push_back(current_info); mDurationFullBucket += mDuration; if (eventTimeNs > fullBucketEnd) { // End of full bucket, can send to anomaly tracker now. - addPastBucketToAnomalyTrackers(mDurationFullBucket, current_info.mBucketNum); + addPastBucketToAnomalyTrackers(mDurationFullBucket, mCurrentBucketNum); mDurationFullBucket = 0; } VLOG(" duration: %lld", (long long)current_info.mDuration); @@ -182,12 +181,11 @@ bool OringDurationTracker::flushCurrentBucket( DurationBucket info; info.mBucketStartNs = fullBucketEnd + mBucketSizeNs * (i - 1); info.mBucketEndNs = info.mBucketStartNs + mBucketSizeNs; - info.mBucketNum = mCurrentBucketNum + i; info.mDuration = mBucketSizeNs; (*output)[mEventKey].push_back(info); // Safe to send these buckets to anomaly tracker since they must be full buckets. // If it's a partial bucket, numBucketsForward would be 0. - addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum); + addPastBucketToAnomalyTrackers(info.mDuration, mCurrentBucketNum + i); VLOG(" add filling bucket with duration %lld", (long long)info.mDuration); } } diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 3c5f5a2b9907..0412538ef058 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -46,7 +46,7 @@ message EventMetricData { optional Atom atom = 2; - optional int64 wall_clock_timestamp_sec = 3; + optional int64 wall_clock_timestamp_nanos = 3; } message CountBucketInfo { @@ -105,6 +105,8 @@ message GaugeBucketInfo { repeated Atom atom = 3; repeated int64 elapsed_timestamp_nanos = 4; + + repeated int64 wall_clock_timestamp_nanos = 5; } message GaugeMetricData { @@ -154,6 +156,10 @@ message ConfigMetricsReport { optional int64 last_report_elapsed_nanos = 3; optional int64 current_report_elapsed_nanos = 4; + + optional int64 last_report_wall_clock_nanos = 5; + + optional int64 current_report_wall_clock_nanos = 6; } message ConfigMetricsReportList { diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index 1c99e2ad03bc..2c701915f429 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -31,6 +31,8 @@ enum Position { LAST = 2; ANY = 3; + + ALL = 4; } enum TimeUnit { diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp index 781ecede1700..cd41f533fecf 100644 --- a/cmds/statsd/src/storage/StorageManager.cpp +++ b/cmds/statsd/src/storage/StorageManager.cpp @@ -245,6 +245,45 @@ void StorageManager::readConfigFromDisk(map<ConfigKey, StatsdConfig>& configsMap } } +bool StorageManager::hasIdenticalConfig(const ConfigKey& key, + const vector<uint8_t>& config) { + unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), + closedir); + if (dir == NULL) { + VLOG("Directory does not exist: %s", STATS_SERVICE_DIR); + return false; + } + + const char* suffix = + StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId()).c_str(); + + dirent* de; + while ((de = readdir(dir.get()))) { + char* name = de->d_name; + if (name[0] == '.') { + continue; + } + size_t nameLen = strlen(name); + size_t suffixLen = strlen(suffix); + // There can be at most one file that matches this suffix (config key). + if (suffixLen <= nameLen && + strncmp(name + nameLen - suffixLen, suffix, suffixLen) == 0) { + int fd = open(StringPrintf("%s/%s", STATS_SERVICE_DIR, name).c_str(), + O_RDONLY | O_CLOEXEC); + if (fd != -1) { + string content; + if (android::base::ReadFdToString(fd, &content)) { + vector<uint8_t> vec(content.begin(), content.end()); + if (vec == config) { + return true; + } + } + } + } + } + return false; +} + void StorageManager::trimToFit(const char* path) { unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir); if (dir == NULL) { @@ -306,6 +345,53 @@ void StorageManager::trimToFit(const char* path) { } } +void StorageManager::printStats(FILE* out) { + printDirStats(out, STATS_SERVICE_DIR); + printDirStats(out, STATS_DATA_DIR); +} + +void StorageManager::printDirStats(FILE* out, const char* path) { + fprintf(out, "Printing stats of %s\n", path); + unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir); + if (dir == NULL) { + VLOG("Path %s does not exist", path); + return; + } + dirent* de; + int fileCount = 0; + int totalFileSize = 0; + while ((de = readdir(dir.get()))) { + char* name = de->d_name; + if (name[0] == '.') { + continue; + } + int64_t result[3]; + parseFileName(name, result); + if (result[0] == -1) continue; + int64_t timestamp = result[0]; + int64_t uid = result[1]; + int64_t configID = result[2]; + fprintf(out, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld", + fileCount + 1, + (long long)timestamp, + (int)uid, + (long long)configID); + string file_name = getFilePath(path, timestamp, uid, configID); + ifstream file(file_name.c_str(), ifstream::in | ifstream::binary); + if (file.is_open()) { + file.seekg(0, ios::end); + int fileSize = file.tellg(); + file.close(); + fprintf(out, ", File Size: %d bytes", fileSize); + totalFileSize += fileSize; + } + fprintf(out, "\n"); + fileCount++; + } + fprintf(out, "\tTotal number of files: %d, Total size of files: %d bytes.\n", + fileCount, totalFileSize); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h index 6c8ed0a96704..4b7562855f30 100644 --- a/cmds/statsd/src/storage/StorageManager.h +++ b/cmds/statsd/src/storage/StorageManager.h @@ -78,6 +78,23 @@ public: * files, accumulation of outdated files. */ static void trimToFit(const char* dir); + + /** + * Returns true if there already exists identical configuration on device. + */ + static bool hasIdenticalConfig(const ConfigKey& key, + const vector<uint8_t>& config); + + /** + * Prints disk usage statistics related to statsd. + */ + static void printStats(FILE* out); + +private: + /** + * Prints disk usage statistics about a directory related to statsd. + */ + static void printDirStats(FILE* out, const char* path); }; } // namespace statsd diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp index 5846761cb8e9..73e7c44dc3da 100644 --- a/cmds/statsd/tests/FieldValue_test.cpp +++ b/cmds/statsd/tests/FieldValue_test.cpp @@ -45,20 +45,41 @@ TEST(AtomMatcherTest, TestFieldTranslation) { const auto& matcher12 = output[0]; EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag()); - EXPECT_EQ((int32_t)0x2010001, matcher12.mMatcher.getField()); + EXPECT_EQ((int32_t)0x02010001, matcher12.mMatcher.getField()); EXPECT_EQ((int32_t)0xff7f007f, matcher12.mMask); } -TEST(AtomMatcherTest, TestFilter) { +TEST(AtomMatcherTest, TestFieldTranslation_ALL) { FieldMatcher matcher1; matcher1.set_field(10); FieldMatcher* child = matcher1.add_child(); child->set_field(1); - child->set_position(Position::ANY); + child->set_position(Position::ALL); child = child->add_child(); child->set_field(1); + vector<Matcher> output; + translateFieldMatcher(matcher1, &output); + + EXPECT_EQ((size_t)1, output.size()); + + const auto& matcher12 = output[0]; + EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag()); + EXPECT_EQ((int32_t)0x02010001, matcher12.mMatcher.getField()); + EXPECT_EQ((int32_t)0xff7f7f7f, matcher12.mMask); +} + +TEST(AtomMatcherTest, TestFilter_ALL) { + FieldMatcher matcher1; + matcher1.set_field(10); + FieldMatcher* child = matcher1.add_child(); + child->set_field(1); + child->set_position(Position::ALL); + + child->add_child()->set_field(1); + child->add_child()->set_field(2); + child = matcher1.add_child(); child->set_field(2); @@ -85,32 +106,28 @@ TEST(AtomMatcherTest, TestFilter) { event.write("some value"); // Convert to a LogEvent event.init(); - vector<HashableDimensionKey> output; + HashableDimensionKey output; filterValues(matchers, event.getValues(), &output); - EXPECT_EQ((size_t)(3), output.size()); - - const auto& key1 = output[0]; - EXPECT_EQ((size_t)2, key1.getValues().size()); - EXPECT_EQ((int32_t)0x02010001, key1.getValues()[0].mField.getField()); - EXPECT_EQ((int32_t)1111, key1.getValues()[0].mValue.int_value); - EXPECT_EQ((int32_t)0x00020000, key1.getValues()[1].mField.getField()); - EXPECT_EQ("some value", key1.getValues()[1].mValue.str_value); - - const auto& key2 = output[1]; - EXPECT_EQ((size_t)2, key2.getValues().size()); - EXPECT_EQ((int32_t)0x02010001, key2.getValues()[0].mField.getField()); - EXPECT_EQ((int32_t)2222, key2.getValues()[0].mValue.int_value); - EXPECT_EQ((int32_t)0x00020000, key2.getValues()[1].mField.getField()); - EXPECT_EQ("some value", key2.getValues()[1].mValue.str_value); - - const auto& key3 = output[2]; - EXPECT_EQ((size_t)2, key3.getValues().size()); - EXPECT_EQ((int32_t)0x02010001, key3.getValues()[0].mField.getField()); - EXPECT_EQ((int32_t)3333, key3.getValues()[0].mValue.int_value); - EXPECT_EQ((int32_t)0x00020000, key3.getValues()[1].mField.getField()); - EXPECT_EQ("some value", key3.getValues()[1].mValue.str_value); + EXPECT_EQ((size_t)7, output.getValues().size()); + EXPECT_EQ((int32_t)0x02010101, output.getValues()[0].mField.getField()); + EXPECT_EQ((int32_t)1111, output.getValues()[0].mValue.int_value); + EXPECT_EQ((int32_t)0x02010102, output.getValues()[1].mField.getField()); + EXPECT_EQ("location1", output.getValues()[1].mValue.str_value); + + EXPECT_EQ((int32_t)0x02010201, output.getValues()[2].mField.getField()); + EXPECT_EQ((int32_t)2222, output.getValues()[2].mValue.int_value); + EXPECT_EQ((int32_t)0x02010202, output.getValues()[3].mField.getField()); + EXPECT_EQ("location2", output.getValues()[3].mValue.str_value); + + EXPECT_EQ((int32_t)0x02010301, output.getValues()[4].mField.getField()); + EXPECT_EQ((int32_t)3333, output.getValues()[4].mValue.int_value); + EXPECT_EQ((int32_t)0x02010302, output.getValues()[5].mField.getField()); + EXPECT_EQ("location3", output.getValues()[5].mValue.str_value); + + EXPECT_EQ((int32_t)0x00020000, output.getValues()[6].mField.getField()); + EXPECT_EQ("some value", output.getValues()[6].mValue.str_value); } TEST(AtomMatcherTest, TestSubDimension) { diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp index 7a7e000fb98f..2574ba79f9d3 100644 --- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp @@ -28,7 +28,7 @@ namespace statsd { namespace { -StatsdConfig CreateStatsdConfig() { +StatsdConfig CreateStatsdConfig(const Position position) { StatsdConfig config; auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher(); auto attributionNodeMatcher = @@ -46,15 +46,15 @@ StatsdConfig CreateStatsdConfig() { countMetric->set_what(wakelockAcquireMatcher.id()); *countMetric->mutable_dimensions_in_what() = CreateAttributionUidAndTagDimensions( - android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); + android::util::WAKELOCK_STATE_CHANGED, {position}); countMetric->set_bucket(FIVE_MINUTES); return config; } } // namespace -TEST(AttributionE2eTest, TestAttributionMatchAndSlice) { - auto config = CreateStatsdConfig(); +TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) { + auto config = CreateStatsdConfig(Position::FIRST); int64_t bucketStartTimeNs = 10000000000; int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; @@ -199,6 +199,215 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSlice) { EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs); } +TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) { + auto config = CreateStatsdConfig(Position::ALL); + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + + // Here it assumes that GMS core has two uids. + processor->getUidMap()->updateApp( + android::String16("com.android.gmscore"), 222 /* uid */, 1 /* version code*/); + processor->getUidMap()->updateApp( + android::String16("com.android.gmscore"), 444 /* uid */, 1 /* version code*/); + processor->getUidMap()->updateApp( + android::String16("app1"), 111 /* uid */, 2 /* version code*/); + processor->getUidMap()->updateApp( + android::String16("APP3"), 333 /* uid */, 2 /* version code*/); + + // GMS core node is in the middle. + std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"), + CreateAttribution(222, "GMSCoreModule1"), + CreateAttribution(333, "App3")}; + + // GMS core node is the last one. + std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"), + CreateAttribution(333, "App3"), + CreateAttribution(222, "GMSCoreModule1")}; + + // GMS core node is the first one. + std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"), + CreateAttribution(333, "App3")}; + + // Single GMS core node. + std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")}; + + // GMS core has another uid. + std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"), + CreateAttribution(444, "GMSCoreModule2"), + CreateAttribution(333, "App3")}; + + // Multiple GMS core nodes. + std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"), + CreateAttribution(222, "GMSCoreModule1")}; + + // No GMS core nodes. + std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"), + CreateAttribution(333, "App3")}; + std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")}; + + // GMS core node with isolated uid. + const int isolatedUid = 666; + std::vector<AttributionNodeInternal> attributions9 = { + CreateAttribution(isolatedUid, "GMSCoreModule1")}; + + std::vector<std::unique_ptr<LogEvent>> events; + // Events 1~4 are in the 1st bucket. + events.push_back(CreateAcquireWakelockEvent( + attributions1, "wl1", bucketStartTimeNs + 2)); + events.push_back(CreateAcquireWakelockEvent( + attributions2, "wl1", bucketStartTimeNs + 200)); + events.push_back(CreateAcquireWakelockEvent( + attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1)); + events.push_back(CreateAcquireWakelockEvent( + attributions4, "wl1", bucketStartTimeNs + bucketSizeNs)); + + // Events 5~8 are in the 3rd bucket. + events.push_back(CreateAcquireWakelockEvent( + attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1)); + events.push_back(CreateAcquireWakelockEvent( + attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100)); + events.push_back(CreateAcquireWakelockEvent( + attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2)); + events.push_back(CreateAcquireWakelockEvent( + attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs)); + events.push_back(CreateAcquireWakelockEvent( + attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1)); + events.push_back(CreateAcquireWakelockEvent( + attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100)); + events.push_back(CreateIsolatedUidChangedEvent( + isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1)); + events.push_back(CreateIsolatedUidChangedEvent( + isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10)); + + sortLogEventsByTimestamp(&events); + + for (const auto& event : events) { + processor->OnLogEvent(event.get()); + } + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, &buffer); + EXPECT_TRUE(buffer.size() > 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + EXPECT_EQ(reports.reports_size(), 1); + EXPECT_EQ(reports.reports(0).metrics_size(), 1); + + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(countMetrics.data_size(), 6); + + auto data = countMetrics.data(0); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(1, data.bucket_info(1).count()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, + data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, + data.bucket_info(1).end_bucket_elapsed_nanos()); + + data = countMetrics.data(1); + ValidateUidDimension( + data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); + ValidateUidDimension( + data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); + EXPECT_EQ(data.bucket_info_size(), 1); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs); + EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs); + + data = countMetrics.data(2); + ValidateUidDimension( + data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2"); + ValidateUidDimension( + data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); + EXPECT_EQ(data.bucket_info_size(), 1); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(3); + ValidateUidDimension( + data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); + ValidateUidDimension( + data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); + ValidateUidDimension( + data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); + EXPECT_EQ(data.bucket_info_size(), 1); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(bucketStartTimeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(4); + ValidateUidDimension( + data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); + ValidateUidDimension( + data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); + ValidateUidDimension( + data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); + EXPECT_EQ(data.bucket_info_size(), 1); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(bucketStartTimeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(5); + ValidateUidDimension( + data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); + ValidateUidDimension( + data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2"); + ValidateUidDimension( + data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333); + ValidateAttributionUidAndTagDimension( + data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); + EXPECT_EQ(data.bucket_info_size(), 1); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, + data.bucket_info(0).end_bucket_elapsed_nanos()); +} + #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp new file mode 100644 index 000000000000..9ceffc816e68 --- /dev/null +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp @@ -0,0 +1,281 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <gtest/gtest.h> + +#include "src/StatsLogProcessor.h" +#include "src/stats_log_util.h" +#include "tests/statsd_test_util.h" + +#include <vector> + +namespace android { +namespace os { +namespace statsd { + +#ifdef __ANDROID__ + +namespace { + +StatsdConfig CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sampling_type) { + StatsdConfig config; + *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); + *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); + + auto atomMatcher = CreateSimpleAtomMatcher("", android::util::APP_START_CHANGED); + *config.add_atom_matcher() = atomMatcher; + + auto isInBackgroundPredicate = CreateIsInBackgroundPredicate(); + *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() = + CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ }); + *config.add_predicate() = isInBackgroundPredicate; + + auto gaugeMetric = config.add_gauge_metric(); + gaugeMetric->set_id(123456); + gaugeMetric->set_what(atomMatcher.id()); + gaugeMetric->set_condition(isInBackgroundPredicate.id()); + gaugeMetric->mutable_gauge_fields_filter()->set_include_all(false); + gaugeMetric->set_sampling_type(sampling_type); + auto fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields(); + fieldMatcher->set_field(android::util::APP_START_CHANGED); + fieldMatcher->add_child()->set_field(3); // type (enum) + fieldMatcher->add_child()->set_field(4); // activity_name(str) + fieldMatcher->add_child()->set_field(7); // activity_start_msec(int64) + *gaugeMetric->mutable_dimensions_in_what() = + CreateDimensions(android::util::APP_START_CHANGED, {1 /* uid field */ }); + gaugeMetric->set_bucket(FIVE_MINUTES); + + auto links = gaugeMetric->add_links(); + links->set_condition(isInBackgroundPredicate.id()); + auto dimensionWhat = links->mutable_fields_in_what(); + dimensionWhat->set_field(android::util::APP_START_CHANGED); + dimensionWhat->add_child()->set_field(1); // uid field. + auto dimensionCondition = links->mutable_fields_in_condition(); + dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED); + dimensionCondition->add_child()->set_field(1); // uid field. + return config; +} + +std::unique_ptr<LogEvent> CreateAppStartChangedEvent( + const int uid, const string& pkg_name, AppStartChanged::TransitionType type, + const string& activity_name, const string& calling_pkg_name, const bool is_instant_app, + int64_t activity_start_msec, uint64_t timestampNs) { + auto logEvent = std::make_unique<LogEvent>( + android::util::APP_START_CHANGED, timestampNs); + logEvent->write(uid); + logEvent->write(pkg_name); + logEvent->write(type); + logEvent->write(activity_name); + logEvent->write(calling_pkg_name); + logEvent->write(is_instant_app); + logEvent->write(activity_start_msec); + logEvent->init(); + return logEvent; +} + +} // namespace + +TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { + for (const auto& sampling_type : + { GaugeMetric::ALL_CONDITION_CHANGES, GaugeMetric:: RANDOM_ONE_SAMPLE }) { + auto config = CreateStatsdConfigForPushedEvent(sampling_type); + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + + int appUid1 = 123; + int appUid2 = 456; + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + 15)); + events.push_back(CreateMoveToForegroundEvent( + appUid1, bucketStartTimeNs + bucketSizeNs + 250)); + events.push_back(CreateMoveToBackgroundEvent( + appUid1, bucketStartTimeNs + bucketSizeNs + 350)); + events.push_back(CreateMoveToForegroundEvent( + appUid1, bucketStartTimeNs + 2 * bucketSizeNs + 100)); + + + events.push_back(CreateAppStartChangedEvent( + appUid1, "app1", AppStartChanged::WARM, "activity_name1", "calling_pkg_name1", + true /*is_instant_app*/, 101 /*activity_start_msec*/, bucketStartTimeNs + 10)); + events.push_back(CreateAppStartChangedEvent( + appUid1, "app1", AppStartChanged::HOT, "activity_name2", "calling_pkg_name2", + true /*is_instant_app*/, 102 /*activity_start_msec*/, bucketStartTimeNs + 20)); + events.push_back(CreateAppStartChangedEvent( + appUid1, "app1", AppStartChanged::COLD, "activity_name3", "calling_pkg_name3", + true /*is_instant_app*/, 103 /*activity_start_msec*/, bucketStartTimeNs + 30)); + events.push_back(CreateAppStartChangedEvent( + appUid1, "app1", AppStartChanged::WARM, "activity_name4", "calling_pkg_name4", + true /*is_instant_app*/, 104 /*activity_start_msec*/, + bucketStartTimeNs + bucketSizeNs + 30)); + events.push_back(CreateAppStartChangedEvent( + appUid1, "app1", AppStartChanged::COLD, "activity_name5", "calling_pkg_name5", + true /*is_instant_app*/, 105 /*activity_start_msec*/, + bucketStartTimeNs + 2 * bucketSizeNs)); + events.push_back(CreateAppStartChangedEvent( + appUid1, "app1", AppStartChanged::HOT, "activity_name6", "calling_pkg_name6", + false /*is_instant_app*/, 106 /*activity_start_msec*/, + bucketStartTimeNs + 2 * bucketSizeNs + 10)); + + events.push_back(CreateMoveToBackgroundEvent( + appUid2, bucketStartTimeNs + bucketSizeNs + 10)); + events.push_back(CreateAppStartChangedEvent( + appUid2, "app2", AppStartChanged::COLD, "activity_name7", "calling_pkg_name7", + true /*is_instant_app*/, 201 /*activity_start_msec*/, + bucketStartTimeNs + 2 * bucketSizeNs + 10)); + + sortLogEventsByTimestamp(&events); + + for (const auto& event : events) { + processor->OnLogEvent(event.get()); + } + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, &buffer); + EXPECT_TRUE(buffer.size() > 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; + sortMetricDataByDimensionsValue( + reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); + EXPECT_EQ(2, gaugeMetrics.data_size()); + + auto data = gaugeMetrics.data(0); + EXPECT_EQ(android::util::APP_START_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(3, data.bucket_info_size()); + if (sampling_type == GaugeMetric::ALL_CONDITION_CHANGES) { + EXPECT_EQ(2, data.bucket_info(0).atom_size()); + EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size()); + EXPECT_EQ(2, data.bucket_info(0).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_nanos()); + EXPECT_EQ(AppStartChanged::HOT, data.bucket_info(0).atom(0).app_start_changed().type()); + EXPECT_EQ("activity_name2", + data.bucket_info(0).atom(0).app_start_changed().activity_name()); + EXPECT_EQ(102L, + data.bucket_info(0).atom(0).app_start_changed().activity_start_millis()); + EXPECT_EQ(AppStartChanged::COLD, + data.bucket_info(0).atom(1).app_start_changed().type()); + EXPECT_EQ("activity_name3", + data.bucket_info(0).atom(1).app_start_changed().activity_name()); + EXPECT_EQ(103L, + data.bucket_info(0).atom(1).app_start_changed().activity_start_millis()); + + EXPECT_EQ(1, data.bucket_info(1).atom_size()); + EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size()); + EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(1).start_bucket_nanos()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(1).end_bucket_nanos()); + EXPECT_EQ(AppStartChanged::WARM, + data.bucket_info(1).atom(0).app_start_changed().type()); + EXPECT_EQ("activity_name4", + data.bucket_info(1).atom(0).app_start_changed().activity_name()); + EXPECT_EQ(104L, + data.bucket_info(1).atom(0).app_start_changed().activity_start_millis()); + + EXPECT_EQ(2, data.bucket_info(2).atom_size()); + EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size()); + EXPECT_EQ(2, data.bucket_info(2).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(2).start_bucket_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, + data.bucket_info(2).end_bucket_nanos()); + EXPECT_EQ(AppStartChanged::COLD, + data.bucket_info(2).atom(0).app_start_changed().type()); + EXPECT_EQ("activity_name5", + data.bucket_info(2).atom(0).app_start_changed().activity_name()); + EXPECT_EQ(105L, + data.bucket_info(2).atom(0).app_start_changed().activity_start_millis()); + EXPECT_EQ(AppStartChanged::HOT, + data.bucket_info(2).atom(1).app_start_changed().type()); + EXPECT_EQ("activity_name6", + data.bucket_info(2).atom(1).app_start_changed().activity_name()); + EXPECT_EQ(106L, + data.bucket_info(2).atom(1).app_start_changed().activity_start_millis()); + } else { + EXPECT_EQ(1, data.bucket_info(0).atom_size()); + EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); + EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_nanos()); + EXPECT_EQ(AppStartChanged::HOT, data.bucket_info(0).atom(0).app_start_changed().type()); + EXPECT_EQ("activity_name2", + data.bucket_info(0).atom(0).app_start_changed().activity_name()); + EXPECT_EQ(102L, + data.bucket_info(0).atom(0).app_start_changed().activity_start_millis()); + + EXPECT_EQ(1, data.bucket_info(1).atom_size()); + EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size()); + EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(1).start_bucket_nanos()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(1).end_bucket_nanos()); + EXPECT_EQ(AppStartChanged::WARM, + data.bucket_info(1).atom(0).app_start_changed().type()); + EXPECT_EQ("activity_name4", + data.bucket_info(1).atom(0).app_start_changed().activity_name()); + EXPECT_EQ(104L, + data.bucket_info(1).atom(0).app_start_changed().activity_start_millis()); + + EXPECT_EQ(1, data.bucket_info(2).atom_size()); + EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size()); + EXPECT_EQ(1, data.bucket_info(2).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(2).start_bucket_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, + data.bucket_info(2).end_bucket_nanos()); + EXPECT_EQ(AppStartChanged::COLD, + data.bucket_info(2).atom(0).app_start_changed().type()); + EXPECT_EQ("activity_name5", + data.bucket_info(2).atom(0).app_start_changed().activity_name()); + EXPECT_EQ(105L, + data.bucket_info(2).atom(0).app_start_changed().activity_start_millis()); + } + + data = gaugeMetrics.data(1); + + EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_CHANGED); + EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).atom_size()); + EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); + EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_nanos()); + EXPECT_EQ(AppStartChanged::COLD, data.bucket_info(0).atom(0).app_start_changed().type()); + EXPECT_EQ("activity_name7", + data.bucket_info(0).atom(0).app_start_changed().activity_name()); + EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_changed().activity_start_millis()); + } +} + +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp deleted file mode 100644 index 3843e0a3c67d..000000000000 --- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (C) 2017 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include <gtest/gtest.h> - -#include "src/StatsLogProcessor.h" -#include "src/stats_log_util.h" -#include "tests/statsd_test_util.h" - -#include <vector> - -namespace android { -namespace os { -namespace statsd { - -#ifdef __ANDROID__ - -namespace { - -StatsdConfig CreateStatsdConfigForPushedEvent() { - StatsdConfig config; - *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); - *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); - - auto atomMatcher = CreateSimpleAtomMatcher("", android::util::APP_START_CHANGED); - *config.add_atom_matcher() = atomMatcher; - - auto isInBackgroundPredicate = CreateIsInBackgroundPredicate(); - *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() = - CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ }); - *config.add_predicate() = isInBackgroundPredicate; - - auto gaugeMetric = config.add_gauge_metric(); - gaugeMetric->set_id(123456); - gaugeMetric->set_what(atomMatcher.id()); - gaugeMetric->set_condition(isInBackgroundPredicate.id()); - gaugeMetric->mutable_gauge_fields_filter()->set_include_all(false); - auto fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields(); - fieldMatcher->set_field(android::util::APP_START_CHANGED); - fieldMatcher->add_child()->set_field(3); // type (enum) - fieldMatcher->add_child()->set_field(4); // activity_name(str) - fieldMatcher->add_child()->set_field(7); // activity_start_msec(int64) - *gaugeMetric->mutable_dimensions_in_what() = - CreateDimensions(android::util::APP_START_CHANGED, {1 /* uid field */ }); - gaugeMetric->set_bucket(FIVE_MINUTES); - - auto links = gaugeMetric->add_links(); - links->set_condition(isInBackgroundPredicate.id()); - auto dimensionWhat = links->mutable_fields_in_what(); - dimensionWhat->set_field(android::util::APP_START_CHANGED); - dimensionWhat->add_child()->set_field(1); // uid field. - auto dimensionCondition = links->mutable_fields_in_condition(); - dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED); - dimensionCondition->add_child()->set_field(1); // uid field. - return config; -} - -std::unique_ptr<LogEvent> CreateAppStartChangedEvent( - const int uid, const string& pkg_name, AppStartChanged::TransitionType type, - const string& activity_name, const string& calling_pkg_name, const bool is_instant_app, - int64_t activity_start_msec, uint64_t timestampNs) { - auto logEvent = std::make_unique<LogEvent>( - android::util::APP_START_CHANGED, timestampNs); - logEvent->write(uid); - logEvent->write(pkg_name); - logEvent->write(type); - logEvent->write(activity_name); - logEvent->write(calling_pkg_name); - logEvent->write(is_instant_app); - logEvent->write(activity_start_msec); - logEvent->init(); - return logEvent; -} - -} // namespace - -TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { - auto config = CreateStatsdConfigForPushedEvent(); - int64_t bucketStartTimeNs = 10000000000; - int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; - - ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey); - EXPECT_EQ(processor->mMetricsManagers.size(), 1u); - EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); - - int appUid1 = 123; - int appUid2 = 456; - std::vector<std::unique_ptr<LogEvent>> events; - events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + 15)); - events.push_back(CreateMoveToForegroundEvent(appUid1, bucketStartTimeNs + bucketSizeNs + 250)); - events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + bucketSizeNs + 350)); - events.push_back(CreateMoveToForegroundEvent( - appUid1, bucketStartTimeNs + 2 * bucketSizeNs + 100)); - - - events.push_back(CreateAppStartChangedEvent( - appUid1, "app1", AppStartChanged::WARM, "activity_name1", "calling_pkg_name1", - true /*is_instant_app*/, 101 /*activity_start_msec*/, bucketStartTimeNs + 10)); - events.push_back(CreateAppStartChangedEvent( - appUid1, "app1", AppStartChanged::HOT, "activity_name2", "calling_pkg_name2", - true /*is_instant_app*/, 102 /*activity_start_msec*/, bucketStartTimeNs + 20)); - events.push_back(CreateAppStartChangedEvent( - appUid1, "app1", AppStartChanged::COLD, "activity_name3", "calling_pkg_name3", - true /*is_instant_app*/, 103 /*activity_start_msec*/, bucketStartTimeNs + 30)); - events.push_back(CreateAppStartChangedEvent( - appUid1, "app1", AppStartChanged::WARM, "activity_name4", "calling_pkg_name4", - true /*is_instant_app*/, 104 /*activity_start_msec*/, - bucketStartTimeNs + bucketSizeNs + 30)); - events.push_back(CreateAppStartChangedEvent( - appUid1, "app1", AppStartChanged::COLD, "activity_name5", "calling_pkg_name5", - true /*is_instant_app*/, 105 /*activity_start_msec*/, - bucketStartTimeNs + 2 * bucketSizeNs)); - events.push_back(CreateAppStartChangedEvent( - appUid1, "app1", AppStartChanged::HOT, "activity_name6", "calling_pkg_name6", - false /*is_instant_app*/, 106 /*activity_start_msec*/, - bucketStartTimeNs + 2 * bucketSizeNs + 10)); - - events.push_back(CreateMoveToBackgroundEvent(appUid2, bucketStartTimeNs + bucketSizeNs + 10)); - events.push_back(CreateAppStartChangedEvent( - appUid2, "app2", AppStartChanged::COLD, "activity_name7", "calling_pkg_name7", - true /*is_instant_app*/, 201 /*activity_start_msec*/, - bucketStartTimeNs + 2 * bucketSizeNs + 10)); - - sortLogEventsByTimestamp(&events); - - for (const auto& event : events) { - processor->OnLogEvent(event.get()); - } - ConfigMetricsReportList reports; - vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, &buffer); - EXPECT_TRUE(buffer.size() > 0); - EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); - EXPECT_EQ(reports.reports_size(), 1); - EXPECT_EQ(reports.reports(0).metrics_size(), 1); - StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; - sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); - EXPECT_EQ(gaugeMetrics.data_size(), 2); - - auto data = gaugeMetrics.data(0); - EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_CHANGED); - EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1); - EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1 /* uid field */); - EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid1); - EXPECT_EQ(data.bucket_info_size(), 3); - EXPECT_EQ(data.bucket_info(0).atom_size(), 1); - EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs); - EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs); - EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().type(), AppStartChanged::HOT); - EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_name(), "activity_name2"); - EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_millis(), 102L); - - EXPECT_EQ(data.bucket_info(1).atom_size(), 1); - EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs); - EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs); - EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().type(), AppStartChanged::WARM); - EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_name(), "activity_name4"); - EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_start_millis(), 104L); - - EXPECT_EQ(data.bucket_info(2).atom_size(), 1); - EXPECT_EQ(data.bucket_info(2).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs); - EXPECT_EQ(data.bucket_info(2).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs); - EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().type(), AppStartChanged::COLD); - EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_name(), "activity_name5"); - EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_start_millis(), 105L); - - data = gaugeMetrics.data(1); - - EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_CHANGED); - EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1); - EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1 /* uid field */); - EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid2); - EXPECT_EQ(data.bucket_info_size(), 1); - EXPECT_EQ(data.bucket_info(0).atom_size(), 1); - EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs); - EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs); - EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().type(), AppStartChanged::COLD); - EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_name(), "activity_name7"); - EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_millis(), 201L); -} - -#else -GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif - -} // namespace statsd -} // namespace os -} // namespace android diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp index 77b3ace90aff..c0cc0b6ad218 100644 --- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp @@ -112,7 +112,6 @@ TEST(GaugeMetricProducerTest, TestNoCondition) { it++; EXPECT_EQ(INT, it->mValue.getType()); EXPECT_EQ(11L, it->mValue.int_value); - EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum); gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs); EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size()); @@ -125,7 +124,6 @@ TEST(GaugeMetricProducerTest, TestNoCondition) { it++; EXPECT_EQ(INT, it->mValue.getType()); EXPECT_EQ(25L, it->mValue.int_value); - EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum); } TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) { @@ -337,7 +335,6 @@ TEST(GaugeMetricProducerTest, TestWithCondition) { .mGaugeAtoms.front() .mFields->begin() ->mValue.int_value); - EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum); } TEST(GaugeMetricProducerTest, TestAnomalyDetection) { diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index 2678c8a93463..0f785dff8e81 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -500,12 +500,42 @@ void ValidateUidDimension(const DimensionsValue& value, int atomId, int uid) { .value_tuple().dimensions_value(0).value_int(), uid); } +void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid) { + EXPECT_EQ(value.field(), atomId); + EXPECT_GT(value.value_tuple().dimensions_value_size(), node_idx); + // Attribution field. + EXPECT_EQ(value.value_tuple().dimensions_value(node_idx).field(), 1); + EXPECT_EQ(value.value_tuple().dimensions_value(node_idx) + .value_tuple().dimensions_value(0).field(), 1); + EXPECT_EQ(value.value_tuple().dimensions_value(node_idx) + .value_tuple().dimensions_value(0).value_int(), uid); +} + +void ValidateAttributionUidAndTagDimension( + const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag) { + EXPECT_EQ(value.field(), atomId); + EXPECT_GT(value.value_tuple().dimensions_value_size(), node_idx); + // Attribution field. + EXPECT_EQ(1, value.value_tuple().dimensions_value(node_idx).field()); + // Uid only. + EXPECT_EQ(2, value.value_tuple().dimensions_value(node_idx) + .value_tuple().dimensions_value_size()); + EXPECT_EQ(1, value.value_tuple().dimensions_value(node_idx) + .value_tuple().dimensions_value(0).field()); + EXPECT_EQ(uid, value.value_tuple().dimensions_value(node_idx) + .value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(2, value.value_tuple().dimensions_value(node_idx) + .value_tuple().dimensions_value(1).field()); + EXPECT_EQ(tag, value.value_tuple().dimensions_value(node_idx) + .value_tuple().dimensions_value(1).value_str()); +} + void ValidateAttributionUidAndTagDimension( const DimensionsValue& value, int atomId, int uid, const std::string& tag) { EXPECT_EQ(value.field(), atomId); - EXPECT_EQ(value.value_tuple().dimensions_value_size(), 1); + EXPECT_EQ(1, value.value_tuple().dimensions_value_size()); // Attribution field. - EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1); + EXPECT_EQ(1, value.value_tuple().dimensions_value(0).field()); // Uid only. EXPECT_EQ(value.value_tuple().dimensions_value(0) .value_tuple().dimensions_value_size(), 2); diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h index 14eba1f67d9d..1ac630ccff96 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -180,9 +180,12 @@ void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events); int64_t StringToId(const string& str); +void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid); void ValidateAttributionUidDimension(const DimensionsValue& value, int atomId, int uid); void ValidateAttributionUidAndTagDimension( const DimensionsValue& value, int atomId, int uid, const std::string& tag); +void ValidateAttributionUidAndTagDimension( + const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag); struct DimensionsPair { DimensionsPair(DimensionsValue m1, DimensionsValue m2) : dimInWhat(m1), dimInCondition(m2){}; diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index f134e5488937..06e108c56b7f 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -96,6 +96,7 @@ Landroid/app/ActivityThread;->mLocalProviders:Landroid/util/ArrayMap; Landroid/app/ActivityThread;->mNumVisibleActivities:I Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap; Landroid/app/ActivityThread;->mProviderMap:Landroid/util/ArrayMap; +Landroid/app/ActivityThread;->mResourcePackages:Landroid/util/ArrayMap; Landroid/app/ActivityThread;->mServices:Landroid/util/ArrayMap; Landroid/app/ActivityThread;->performNewIntents(Landroid/os/IBinder;Ljava/util/List;Z)V Landroid/app/ActivityThread;->performStopActivity(Landroid/os/IBinder;ZLjava/lang/String;)V @@ -116,6 +117,7 @@ Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/Strin Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String;)V +Landroid/app/admin/DevicePolicyManager;->setDefaultSmsApplication(Landroid/content/ComponentName;Ljava/lang/String;)V Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I Landroid/app/admin/SecurityLog$SecurityEvent;-><init>([B)V @@ -502,6 +504,7 @@ Landroid/content/res/Resources;->mTypedArrayPool:Landroid/util/Pools$Synchronize Landroid/content/res/Resources;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V Landroid/content/res/Resources;->updateSystemConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V Landroid/content/res/StringBlock;-><init>(JZ)V +Landroid/content/res/TypedArray;->extractThemeAttrs()[I Landroid/content/res/TypedArray;->getNonConfigurationString(II)Ljava/lang/String; Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z Landroid/content/res/TypedArray;->mAssets:Landroid/content/res/AssetManager; @@ -518,6 +521,7 @@ Landroid/content/res/XmlBlock;-><init>([B)V Landroid/content/res/XmlBlock;->newParser()Landroid/content/res/XmlResourceParser; Landroid/content/res/XmlBlock$Parser;->mBlock:Landroid/content/res/XmlBlock; Landroid/content/res/XmlBlock$Parser;->mParseState:J +Landroid/content/SearchRecentSuggestionsProvider;->mSuggestionProjection:[Ljava/lang/String; Landroid/content/SyncStatusInfo;->lastSuccessTime:J Landroid/database/AbstractCursor;->mExtras:Landroid/os/Bundle; Landroid/database/AbstractCursor;->mNotifyUri:Landroid/net/Uri; @@ -556,6 +560,7 @@ Landroid/graphics/Bitmap;->reinit(IIZ)V Landroid/graphics/Camera;->native_instance:J Landroid/graphics/Canvas;-><init>(J)V Landroid/graphics/Canvas;->release()V +Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mStateIds:Landroid/util/SparseIntArray; Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mTransitions:Landroid/util/LongSparseLongArray; @@ -622,6 +627,8 @@ Landroid/graphics/Movie;->mNativeMovie:J Landroid/graphics/NinePatch$InsetStruct;-><init>(IIIIIIIIFIF)V Landroid/graphics/NinePatch;->mBitmap:Landroid/graphics/Bitmap; Landroid/graphics/Picture;->mNativePicture:J +Landroid/graphics/PorterDuffColorFilter;->setColor(I)V +Landroid/graphics/PorterDuffColorFilter;->setMode(Landroid/graphics/PorterDuff$Mode;)V Landroid/graphics/Region;-><init>(JI)V Landroid/graphics/Region;->mNativeRegion:J Landroid/graphics/SurfaceTexture;->mFrameAvailableListener:J @@ -649,6 +656,8 @@ Landroid/hardware/HardwareBuffer;->mNativeObject:J Landroid/hardware/input/IInputManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/input/IInputManager; Landroid/hardware/input/IInputManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/hardware/input/InputManager;->getInstance()Landroid/hardware/input/InputManager; +Landroid/hardware/input/InputManager;->injectInputEvent(Landroid/view/InputEvent;I)Z +Landroid/hardware/input/InputManager;->INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH:I Landroid/hardware/input/InputManager;->mIm:Landroid/hardware/input/IInputManager; Landroid/hardware/location/IActivityRecognitionHardwareClient$Stub;-><init>()V Landroid/hardware/SerialPort;->mNativeContext:I @@ -656,6 +665,7 @@ Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;->confidenceLevel:I Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;-><init>(II)V Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;->userId:I Landroid/hardware/soundtrigger/SoundTrigger$GenericRecognitionEvent;-><init>(IIZIIIZLandroid/media/AudioFormat;[B)V +Landroid/hardware/soundtrigger/SoundTrigger$GenericSoundModel;-><init>(Ljava/util/UUID;Ljava/util/UUID;[B)V Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;->id:I Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;->locale:Ljava/lang/String; Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionEvent;-><init>(IIZIIIZLandroid/media/AudioFormat;[B[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V @@ -674,6 +684,7 @@ Landroid/hardware/soundtrigger/SoundTriggerModule;->postEventFromNative(Ljava/la Landroid/hardware/soundtrigger/SoundTrigger$ModuleProperties;-><init>(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZIZ)V Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;->captureRequested:Z Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;->data:[B +Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;-><init>(ZZ[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;[B)V Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;->keyphrases:[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra; Landroid/hardware/soundtrigger/SoundTrigger$RecognitionEvent;-><init>(IIZIIIZLandroid/media/AudioFormat;[B)V Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;->data:[B @@ -690,8 +701,13 @@ Landroid/hardware/usb/UsbManager;->getPortStatus(Landroid/hardware/usb/UsbPort;) Landroid/hardware/usb/UsbManager;->setCurrentFunction(Ljava/lang/String;Z)V Landroid/hardware/usb/UsbManager;->setPortRoles(Landroid/hardware/usb/UsbPort;II)V Landroid/hardware/usb/UsbPortStatus;->getCurrentDataRole()I +Landroid/hardware/usb/UsbPortStatus;->getCurrentMode()I +Landroid/hardware/usb/UsbPortStatus;->getCurrentPowerRole()I +Landroid/hardware/usb/UsbPortStatus;->getSupportedRoleCombinations()I Landroid/hardware/usb/UsbPortStatus;->isConnected()Z Landroid/hardware/usb/UsbPortStatus;->isRoleCombinationSupported(II)Z +Landroid/hardware/usb/UsbRequest;->mBuffer:Ljava/nio/ByteBuffer; +Landroid/hardware/usb/UsbRequest;->mLength:I Landroid/hardware/usb/UsbRequest;->mNativeContext:J Landroid/icu/impl/CurrencyData;-><init>()V Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V @@ -890,6 +906,10 @@ Landroid/media/RemoteDisplay;->notifyDisplayDisconnected()V Landroid/media/RemoteDisplay;->notifyDisplayError(I)V Landroid/media/RingtoneManager;->getRingtone(Landroid/content/Context;Landroid/net/Uri;I)Landroid/media/Ringtone; Landroid/media/session/MediaSessionLegacyHelper;->getHelper(Landroid/content/Context;)Landroid/media/session/MediaSessionLegacyHelper; +Landroid/media/soundtrigger/SoundTriggerDetector$EventPayload;->getCaptureSession()Ljava/lang/Integer; +Landroid/media/soundtrigger/SoundTriggerDetector$EventPayload;->getData()[B +Landroid/media/soundtrigger/SoundTriggerManager;->loadSoundModel(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;)I +Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UUID;Landroid/app/PendingIntent;Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I Landroid/media/soundtrigger/SoundTriggerManager;->stopRecognition(Ljava/util/UUID;)I Landroid/media/soundtrigger/SoundTriggerManager;->unloadSoundModel(Ljava/util/UUID;)I Landroid/media/SubtitleController;->mHandler:Landroid/os/Handler; @@ -1556,6 +1576,7 @@ Landroid/service/media/MediaBrowserService;->KEY_MEDIA_ITEM:Ljava/lang/String; Landroid/service/media/MediaBrowserService$Result;->mFlags:I Landroid/service/notification/NotificationListenerService;->registerAsSystemService(Landroid/content/Context;Landroid/content/ComponentName;I)V Landroid/service/notification/NotificationListenerService;->unregisterAsSystemService()V +Landroid/service/voice/AlwaysOnHotwordDetector$EventPayload;->getCaptureSession()Ljava/lang/Integer; Landroid/service/voice/VoiceInteractionService;->isKeyphraseAndLocaleSupportedForHotword(Ljava/lang/String;Ljava/util/Locale;)Z Landroid/service/wallpaper/WallpaperService$Engine;->setFixedSizeAllowed(Z)V Landroid/speech/tts/TextToSpeech;->getCurrentEngine()Ljava/lang/String; @@ -1571,6 +1592,7 @@ Landroid/telephony/CellSignalStrengthLte;->mRssnr:I Landroid/telephony/CellSignalStrengthLte;->mSignalStrength:I Landroid/telephony/CellSignalStrengthWcdma;->mBitErrorRate:I Landroid/telephony/CellSignalStrengthWcdma;->mSignalStrength:I +Landroid/telephony/PhoneNumberUtils;->isLocalEmergencyNumber(Landroid/content/Context;ILjava/lang/String;)Z Landroid/telephony/PhoneStateListener;->mSubId:Ljava/lang/Integer; Landroid/telephony/ServiceState;->newFromBundle(Landroid/os/Bundle;)Landroid/telephony/ServiceState; Landroid/telephony/SignalStrength;->getAsuLevel()I @@ -1595,6 +1617,7 @@ Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_NONE_OR_UNKNOWN:I Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_POOR:I Landroid/telephony/SmsMessage;->getSubId()I Landroid/telephony/SmsMessage;->mWrappedSmsMessage:Lcom/android/internal/telephony/SmsMessageBase; +Landroid/telephony/SubscriptionManager;->getActiveSubscriptionIdList()[I Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoCount()I Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoList()Ljava/util/List; Landroid/telephony/SubscriptionManager;->getDefaultDataSubscriptionInfo()Landroid/telephony/SubscriptionInfo; @@ -1715,7 +1738,9 @@ Landroid/util/NtpTrustedTime;->getCachedNtpTime()J Landroid/util/NtpTrustedTime;->getCachedNtpTimeReference()J Landroid/util/NtpTrustedTime;->getInstance(Landroid/content/Context;)Landroid/util/NtpTrustedTime; Landroid/util/NtpTrustedTime;->hasCache()Z +Landroid/util/Pools$SimplePool;->mPool:[Ljava/lang/Object; Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object; +Landroid/util/Pools$SynchronizedPool;-><init>(I)V Landroid/util/Rational;->mDenominator:I Landroid/util/Rational;->mNumerator:I Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V @@ -1767,6 +1792,7 @@ Landroid/view/InputChannel;->mPtr:J Landroid/view/InputDevice;->addMotionRange(IIFFFFF)V Landroid/view/InputDevice;-><init>(IIILjava/lang/String;IILjava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZZ)V Landroid/view/InputDevice;->isExternal()Z +Landroid/view/InputEvent;->getSequenceNumber()I Landroid/view/InputEventReceiver;->dispatchBatchedInputEventPending()V Landroid/view/InputEventReceiver;->dispatchInputEvent(ILandroid/view/InputEvent;I)V Landroid/view/InputEventSender;->dispatchInputEventFinished(IZ)V @@ -1885,6 +1911,7 @@ Landroid/view/View$AttachInfo;->mStableInsets:Landroid/graphics/Rect; Landroid/view/View;->clearAccessibilityFocus()V Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z Landroid/view/View;->computeOpaqueFlags()V +Landroid/view/ViewConfiguration;->getDoubleTapMinTime()I Landroid/view/ViewConfiguration;->mFadingMarqueeEnabled:Z Landroid/view/ViewConfiguration;->sHasPermanentMenuKeySet:Z Landroid/view/ViewConfiguration;->sHasPermanentMenuKey:Z @@ -2280,6 +2307,7 @@ Lcom/android/ims/internal/uce/presence/PresTupleInfo;-><init>()V Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setContactUri(Ljava/lang/String;)V Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setFeatureTag(Ljava/lang/String;)V Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setTimestamp(Ljava/lang/String;)V +Lcom/android/internal/app/AlertController$RecycleListView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V Lcom/android/internal/app/IAppOpsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IAppOpsService; Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V @@ -2500,7 +2528,13 @@ Lcom/android/internal/view/menu/MenuView$ItemView;->getItemData()Lcom/android/in Lcom/android/okhttp/ConnectionPool;->keepAliveDurationNs:J Lcom/android/okhttp/ConnectionPool;->maxIdleConnections:I Lcom/android/okhttp/ConnectionPool;->systemDefault:Lcom/android/okhttp/ConnectionPool; +Lcom/android/okhttp/HttpUrl;->encodedPath()Ljava/lang/String; +Lcom/android/okhttp/HttpUrl;->query()Ljava/lang/String; Lcom/android/okhttp/internal/http/HttpEngine;->httpStream:Lcom/android/okhttp/internal/http/HttpStream; +Lcom/android/okhttp/internal/http/HttpEngine;->networkRequest:Lcom/android/okhttp/Request; +Lcom/android/okhttp/internal/http/HttpEngine;->networkRequest(Lcom/android/okhttp/Request;)Lcom/android/okhttp/Request; +Lcom/android/okhttp/internal/http/HttpEngine;->priorResponse:Lcom/android/okhttp/Response; +Lcom/android/okhttp/internal/http/HttpEngine;->userResponse:Lcom/android/okhttp/Response; Lcom/android/okhttp/OkHttpClient;->connectionPool:Lcom/android/okhttp/ConnectionPool; Lcom/android/okhttp/OkHttpClient;->DEFAULT_PROTOCOLS:Ljava/util/List; Lcom/android/okhttp/OkHttpClient;->dns:Lcom/android/okhttp/Dns; @@ -2508,6 +2542,14 @@ Lcom/android/okhttp/OkHttpClient;->setProtocols(Ljava/util/List;)Lcom/android/ok Lcom/android/okhttp/OkHttpClient;->setRetryOnConnectionFailure(Z)V Lcom/android/okhttp/okio/ByteString;->readObject(Ljava/io/ObjectInputStream;)V Lcom/android/okhttp/okio/ByteString;->writeObject(Ljava/io/ObjectOutputStream;)V +Lcom/android/okhttp/Request;->headers:Lcom/android/okhttp/Headers; +Lcom/android/okhttp/Request;->method:Ljava/lang/String; +Lcom/android/okhttp/Request;->url:Lcom/android/okhttp/HttpUrl; +Lcom/android/okhttp/Response;->code:I +Lcom/android/okhttp/Response;->headers:Lcom/android/okhttp/Headers; +Lcom/android/okhttp/Response;->message:Ljava/lang/String; +Lcom/android/okhttp/Response;->networkResponse:Lcom/android/okhttp/Response; +Lcom/android/okhttp/Response;->protocol:Lcom/android/okhttp/Protocol; Lcom/android/org/conscrypt/AbstractConscryptSocket;->getAlpnSelectedProtocol()[B Lcom/android/org/conscrypt/AbstractConscryptSocket;->getApplicationProtocol()Ljava/lang/String; Lcom/android/org/conscrypt/AbstractConscryptSocket;->getApplicationProtocols()[Ljava/lang/String; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 05a9861f5a20..14edd31a48cf 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1609,6 +1609,7 @@ public class AppOpsManager { * @param mode The app op mode to set. * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) public void setUidMode(int code, int uid, int mode) { try { mService.setUidMode(code, uid, mode); @@ -1628,7 +1629,7 @@ public class AppOpsManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) + @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) public void setUidMode(String appOp, int uid, int mode) { try { mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode); @@ -1660,6 +1661,7 @@ public class AppOpsManager { /** @hide */ @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) public void setMode(int code, int uid, String packageName, int mode) { try { mService.setMode(code, uid, packageName, mode); @@ -1669,6 +1671,27 @@ public class AppOpsManager { } /** + * Change the operating mode for the given op in the given app package. You must pass + * in both the uid and name of the application whose mode is being modified; if these + * do not match, the modification will not be applied. + * + * @param op The operation to modify. One of the OPSTR_* constants. + * @param uid The user id of the application whose mode will be changed. + * @param packageName The name of the application package name whose mode will + * be changed. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) + public void setMode(String op, int uid, String packageName, int mode) { + try { + mService.setMode(strOpToOp(op), uid, packageName, mode); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Set a non-persisted restriction on an audio operation at a stream-level. * Restrictions are temporary additional constraints imposed on top of the persisted rules * defined by {@link #setMode}. @@ -1679,6 +1702,7 @@ public class AppOpsManager { * @param exceptionPackages Optional list of packages to exclude from the restriction. * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) public void setRestriction(int code, @AttributeUsage int usage, int mode, String[] exceptionPackages) { try { @@ -1690,6 +1714,7 @@ public class AppOpsManager { } /** @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) public void resetAllModes() { try { mService.resetAllModes(mContext.getUserId(), null); diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index 41eeb9acb5ec..4531f53bd86f 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -16,8 +16,6 @@ package android.app; -import java.util.ArrayList; - import android.annotation.CallSuper; import android.content.ComponentCallbacks; import android.content.ComponentCallbacks2; @@ -26,8 +24,11 @@ import android.content.ContextWrapper; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; +import android.util.Log; import android.view.autofill.AutofillManager; +import java.util.ArrayList; + /** * Base class for maintaining global application state. You can provide your own * implementation by creating a subclass and specifying the fully-qualified name @@ -46,6 +47,7 @@ import android.view.autofill.AutofillManager; * </p> */ public class Application extends ContextWrapper implements ComponentCallbacks2 { + private static final String TAG = "Application"; private ArrayList<ComponentCallbacks> mComponentCallbacks = new ArrayList<ComponentCallbacks>(); private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks = @@ -318,6 +320,9 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { if (client != null) { return client; } + if (android.view.autofill.Helper.sVerbose) { + Log.v(TAG, "getAutofillClient(): null on super, trying to find activity thread"); + } // Okay, ppl use the application context when they should not. This breaks // autofill among other things. We pick the focused activity since autofill // interacts only with the currently focused activity and we need the fill @@ -338,9 +343,16 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { continue; } if (activity.getWindow().getDecorView().hasFocus()) { - return record.activity; + if (android.view.autofill.Helper.sVerbose) { + Log.v(TAG, "getAutofillClient(): found activity for " + this + ": " + activity); + } + return activity; } } + if (android.view.autofill.Helper.sVerbose) { + Log.v(TAG, "getAutofillClient(): none of the " + activityCount + " activities on " + + this + " have focus"); + } return null; } } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 13a6be557dae..83d6003b5161 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -763,6 +763,11 @@ public class Notification implements Parcelable public static final String CATEGORY_CALL = "call"; /** + * Notification category: map turn-by-turn navigation. + */ + public static final String CATEGORY_NAVIGATION = "navigation"; + + /** * Notification category: incoming direct message (SMS, instant message, etc.). */ public static final String CATEGORY_MESSAGE = "msg"; @@ -835,6 +840,27 @@ public class Notification implements Parcelable public static final String CATEGORY_REMINDER = "reminder"; /** + * Notification category: extreme car emergencies. + * @hide + */ + @SystemApi + public static final String CATEGORY_CAR_EMERGENCY = "car_emergency"; + + /** + * Notification category: car warnings. + * @hide + */ + @SystemApi + public static final String CATEGORY_CAR_WARNING = "car_warning"; + + /** + * Notification category: general car system information. + * @hide + */ + @SystemApi + public static final String CATEGORY_CAR_INFORMATION = "car_information"; + + /** * One of the predefined notification categories (see the <code>CATEGORY_*</code> constants) * that best describes this Notification. May be used by the system for ranking and filtering. */ diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index 9e9a9c57656b..0d995e866512 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -147,7 +147,10 @@ public class TransactionExecutor { pw.println("Executor:"); dump(pw, prefix); - Slog.wtf(TAG, stringWriter.toString()); + Slog.w(TAG, stringWriter.toString()); + + // Ignore requests for non-existent client records for now. + return; } // Cycle to the state right before the final requested state. diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl index 20ec75a36ad3..74e3c3ee4c81 100644 --- a/core/java/android/app/slice/ISliceManager.aidl +++ b/core/java/android/app/slice/ISliceManager.aidl @@ -27,6 +27,7 @@ interface ISliceManager { SliceSpec[] getPinnedSpecs(in Uri uri, String pkg); int checkSlicePermission(in Uri uri, String pkg, int pid, int uid); void grantPermissionFromUser(in Uri uri, String pkg, String callingPkg, boolean allSlices); + Uri[] getPinnedSlices(String pkg); byte[] getBackupPayload(int user); void applyRestore(in byte[] payload, int user); diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java index 4f3cd63841eb..c5ea9b23fece 100644 --- a/core/java/android/app/slice/SliceManager.java +++ b/core/java/android/app/slice/SliceManager.java @@ -184,6 +184,18 @@ public class SliceManager { } /** + * Get the list of currently pinned slices for this app. + * @see SliceProvider#onSlicePinned + */ + public @NonNull List<Uri> getPinnedSlices() { + try { + return Arrays.asList(mService.getPinnedSlices(mContext.getPackageName())); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Obtains a list of slices that are descendants of the specified Uri. * <p> * Not all slice providers will implement this functionality, in which case, diff --git a/core/java/android/app/slice/SliceSpec.java b/core/java/android/app/slice/SliceSpec.java index 8cc0384c1007..03ffe6df88ce 100644 --- a/core/java/android/app/slice/SliceSpec.java +++ b/core/java/android/app/slice/SliceSpec.java @@ -89,7 +89,7 @@ public final class SliceSpec implements Parcelable { * * @param candidate candidate format of data. * @return true if versions are compatible. - * @see androidx.app.slice.widget.SliceView + * @see androidx.slice.widget.SliceView */ public boolean canRender(@NonNull SliceSpec candidate) { if (!mType.equals(candidate.mType)) return false; diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index f7fb84ba9d0a..4c7e97bcb8da 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -109,11 +109,11 @@ public final class UsageEvents implements Parcelable { public static final int NOTIFICATION_SEEN = 10; /** - * An event type denoting a change in App Standby Bucket. Additional bucket information - * is contained in mBucketAndReason. - * @hide + * An event type denoting a change in App Standby Bucket. The new bucket can be + * retrieved by calling {@link #getStandbyBucket()}. + * + * @see UsageStatsManager#getAppStandbyBucket() */ - @SystemApi public static final int STANDBY_BUCKET_CHANGED = 11; /** @@ -254,8 +254,11 @@ public final class UsageEvents implements Parcelable { /** * The event type. * - * See {@link #MOVE_TO_BACKGROUND} - * See {@link #MOVE_TO_FOREGROUND} + * @see #MOVE_TO_BACKGROUND + * @see #MOVE_TO_FOREGROUND + * @see #CONFIGURATION_CHANGE + * @see #USER_INTERACTION + * @see #STANDBY_BUCKET_CHANGED */ public int getEventType() { return mEventType; @@ -283,9 +286,8 @@ public final class UsageEvents implements Parcelable { * Returns the standby bucket of the app, if the event is of type * {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0. * @return the standby bucket associated with the event. - * @hide + * */ - @SystemApi public int getStandbyBucket() { return (mBucketAndReason & 0xFFFF0000) >>> 16; } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 10331d49dd36..ce7d3af8404a 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -2143,21 +2143,6 @@ public abstract class ContentResolver { } /** - * @hide - */ - public void releasePersistableUriPermission(@NonNull String toPackage, @NonNull Uri uri, - @Intent.AccessUriMode int modeFlags) { - Preconditions.checkNotNull(toPackage, "toPackage"); - Preconditions.checkNotNull(uri, "uri"); - try { - ActivityManager.getService().releasePersistableUriPermission( - ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage, - resolveUserId(uri)); - } catch (RemoteException e) { - } - } - - /** * Return list of all URI permission grants that have been persisted by the * calling app. That is, the returned permissions have been granted * <em>to</em> the calling app. Only persistable grants taken with diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index efa90d308ee0..387a836e6961 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -1188,7 +1188,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { if (category != CATEGORY_UNDEFINED) { pw.println(prefix + "category=" + category); } - pw.println("isAllowedToUseHiddenApi=" + isAllowedToUseHiddenApi()); + pw.println(prefix + "isAllowedToUseHiddenApi=" + isAllowedToUseHiddenApi()); } super.dumpBack(pw, prefix); } diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 5b3d3e595a91..dff51f77788e 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -451,6 +451,9 @@ public abstract class PackageManagerInternal { /** Whether the binder caller can access instant apps. */ public abstract boolean canAccessInstantApps(int callingUid, int userId); + /** Whether the binder caller can access the given component. */ + public abstract boolean canAccessComponent(int callingUid, ComponentName component, int userId); + /** * Returns {@code true} if a given package has instant application meta-data. * Otherwise, returns {@code false}. Meta-data is state (eg. cookie, app icon, etc) @@ -544,4 +547,18 @@ public abstract class PackageManagerInternal { /** Updates the flags for the given permission. */ public abstract void updatePermissionFlagsTEMP(@NonNull String permName, @NonNull String packageName, int flagMask, int flagValues, int userId); + + /** + * Returns true if it's still safe to restore data backed up from this app's version + * that was signed with restoringFromSigHash. + */ + public abstract boolean isDataRestoreSafe(@NonNull byte[] restoringFromSigHash, + @NonNull String packageName); + + /** + * Returns true if it's still safe to restore data backed up from this app's version + * that was signed with restoringFromSig. + */ + public abstract boolean isDataRestoreSafe(@NonNull Signature restoringFromSig, + @NonNull String packageName); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 5d5a9782884a..bc7540fabc19 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -3492,7 +3492,7 @@ public class PackageParser { if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic, - true)) { + owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.P)) { ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC; } diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index f47d4640c09c..72db33f90c20 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -819,8 +819,7 @@ public abstract class CameraDevice implements AutoCloseable { * @param config A session configuration (see {@link SessionConfiguration}). * * @throws IllegalArgumentException In case the session configuration is invalid; or the output - * configurations are empty; or the session configuration - * executor is invalid. + * configurations are empty. * @throws CameraAccessException In case the camera device is no longer connected or has * encountered a fatal error. * @see #createCaptureSession(List, CameraCaptureSession.StateCallback, Handler) diff --git a/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java b/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java new file mode 100644 index 000000000000..866f370f5d5d --- /dev/null +++ b/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2014 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.hardware.camera2.dispatch; + +import java.lang.reflect.Method; + +import static com.android.internal.util.Preconditions.*; + +/** + * A dispatcher that replaces one argument with another; replaces any argument at an index + * with another argument. + * + * <p>For example, we can override an {@code void onSomething(int x)} calls to have {@code x} always + * equal to 1. Or, if using this with a duck typing dispatcher, we could even overwrite {@code x} to + * be something + * that's not an {@code int}.</p> + * + * @param <T> + * source dispatch type, whose methods with {@link #dispatch} will be called + * @param <TArg> + * argument replacement type, args in {@link #dispatch} matching {@code argumentIndex} + * will be overriden to objects of this type + */ +public class ArgumentReplacingDispatcher<T, TArg> implements Dispatchable<T> { + + private final Dispatchable<T> mTarget; + private final int mArgumentIndex; + private final TArg mReplaceWith; + + /** + * Create a new argument replacing dispatcher; dispatches are forwarded to {@code target} + * after the argument is replaced. + * + * <p>For example, if a method {@code onAction(T1 a, Integer b, T2 c)} is invoked, and we wanted + * to replace all occurrences of {@code b} with {@code 0xDEADBEEF}, we would set + * {@code argumentIndex = 1} and {@code replaceWith = 0xDEADBEEF}.</p> + * + * <p>If a method dispatched has less arguments than {@code argumentIndex}, it is + * passed through with the arguments unchanged.</p> + * + * @param target destination dispatch type, methods will be redirected to this dispatcher + * @param argumentIndex the numeric index of the argument {@code >= 0} + * @param replaceWith arguments matching {@code argumentIndex} will be replaced with this object + */ + public ArgumentReplacingDispatcher(Dispatchable<T> target, int argumentIndex, + TArg replaceWith) { + mTarget = checkNotNull(target, "target must not be null"); + mArgumentIndex = checkArgumentNonnegative(argumentIndex, + "argumentIndex must not be negative"); + mReplaceWith = checkNotNull(replaceWith, "replaceWith must not be null"); + } + + @Override + public Object dispatch(Method method, Object[] args) throws Throwable { + + if (args.length > mArgumentIndex) { + args = arrayCopy(args); // don't change in-place since it can affect upstream dispatches + args[mArgumentIndex] = mReplaceWith; + } + + return mTarget.dispatch(method, args); + } + + private static Object[] arrayCopy(Object[] array) { + int length = array.length; + Object[] newArray = new Object[length]; + for (int i = 0; i < length; ++i) { + newArray[i] = array[i]; + } + return newArray; + } +} diff --git a/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java b/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java new file mode 100644 index 000000000000..fe575b277616 --- /dev/null +++ b/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 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.hardware.camera2.dispatch; + + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import static com.android.internal.util.Preconditions.*; + +/** + * Broadcast a single dispatch into multiple other dispatchables. + * + * <p>Every time {@link #dispatch} is invoked, all the broadcast targets will + * see the same dispatch as well. The first target's return value is returned.</p> + * + * <p>This enables a single listener to be converted into a multi-listener.</p> + */ +public class BroadcastDispatcher<T> implements Dispatchable<T> { + + private final List<Dispatchable<T>> mDispatchTargets; + + /** + * Create a broadcast dispatcher from the supplied dispatch targets. + * + * @param dispatchTargets one or more targets to dispatch to + */ + @SafeVarargs + public BroadcastDispatcher(Dispatchable<T>... dispatchTargets) { + mDispatchTargets = Arrays.asList( + checkNotNull(dispatchTargets, "dispatchTargets must not be null")); + } + + @Override + public Object dispatch(Method method, Object[] args) throws Throwable { + Object result = null; + boolean gotResult = false; + + for (Dispatchable<T> dispatchTarget : mDispatchTargets) { + Object localResult = dispatchTarget.dispatch(method, args); + + if (!gotResult) { + gotResult = true; + result = localResult; + } + } + + return result; + } +} diff --git a/core/java/android/hardware/camera2/dispatch/Dispatchable.java b/core/java/android/hardware/camera2/dispatch/Dispatchable.java new file mode 100644 index 000000000000..753103f45ea8 --- /dev/null +++ b/core/java/android/hardware/camera2/dispatch/Dispatchable.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 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.hardware.camera2.dispatch; + +import java.lang.reflect.Method; + +/** + * Dynamically dispatch a method and its argument to some object. + * + * <p>This can be used to intercept method calls and do work around them, redirect work, + * or block calls entirely.</p> + */ +public interface Dispatchable<T> { + /** + * Dispatch the method and arguments to this object. + * @param method a method defined in class {@code T} + * @param args arguments corresponding to said {@code method} + * @return the object returned when invoking {@code method} + * @throws Throwable any exception that might have been raised while invoking the method + */ + public Object dispatch(Method method, Object[] args) throws Throwable; +} diff --git a/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java b/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java new file mode 100644 index 000000000000..75f97e4656aa --- /dev/null +++ b/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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.hardware.camera2.dispatch; + + +import java.lang.reflect.Method; + +import static com.android.internal.util.Preconditions.*; + +/** + * Duck typing dispatcher; converts dispatch methods calls from one class to another by + * looking up equivalently methods at runtime by name. + * + * <p>For example, if two types have identical method names and arguments, but + * are not subclasses/subinterfaces of each other, this dispatcher will allow calls to be + * made from one type to the other.</p> + * + * @param <TFrom> source dispatch type, whose methods with {@link #dispatch} will be called + * @param <T> destination dispatch type, methods will be converted to the class of {@code T} + */ +public class DuckTypingDispatcher<TFrom, T> implements Dispatchable<TFrom> { + + private final MethodNameInvoker<T> mDuck; + + /** + * Create a new duck typing dispatcher. + * + * @param target destination dispatch type, methods will be redirected to this dispatcher + * @param targetClass destination dispatch class, methods will be converted to this class's + */ + public DuckTypingDispatcher(Dispatchable<T> target, Class<T> targetClass) { + checkNotNull(targetClass, "targetClass must not be null"); + checkNotNull(target, "target must not be null"); + + mDuck = new MethodNameInvoker<T>(target, targetClass); + } + + @Override + public Object dispatch(Method method, Object[] args) { + return mDuck.invoke(method.getName(), args); + } +} diff --git a/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java b/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java new file mode 100644 index 000000000000..f8e9d49a95c6 --- /dev/null +++ b/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2014 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.hardware.camera2.dispatch; + +import android.hardware.camera2.utils.UncheckedThrow; +import android.os.Handler; +import android.util.Log; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import static com.android.internal.util.Preconditions.*; + +/** + * Forward all interface calls into a handler by posting it as a {@code Runnable}. + * + * <p>All calls will return immediately; functions with return values will return a default + * value of {@code null}, {@code 0}, or {@code false} where that value is legal.</p> + * + * <p>Any exceptions thrown on the handler while trying to invoke a method + * will be re-thrown. Throwing checked exceptions on a handler which doesn't expect any + * checked exceptions to be thrown will result in "undefined" behavior + * (although in practice it is usually thrown as normal).</p> + */ +public class HandlerDispatcher<T> implements Dispatchable<T> { + + private static final String TAG = "HandlerDispatcher"; + + private final Dispatchable<T> mDispatchTarget; + private final Handler mHandler; + + /** + * Create a dispatcher that forwards it's dispatch calls by posting + * them onto the {@code handler} as a {@code Runnable}. + * + * @param dispatchTarget the destination whose method calls will be redirected into the handler + * @param handler all calls into {@code dispatchTarget} will be posted onto this handler + * @param <T> the type of the element you want to wrap. + * @return a dispatcher that will forward it's dispatch calls to a handler + */ + public HandlerDispatcher(Dispatchable<T> dispatchTarget, Handler handler) { + mDispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null"); + mHandler = checkNotNull(handler, "handler must not be null"); + } + + @Override + public Object dispatch(final Method method, final Object[] args) throws Throwable { + mHandler.post(new Runnable() { + @Override + public void run() { + try { + mDispatchTarget.dispatch(method, args); + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + // Potential UB. Hopefully 't' is a runtime exception. + UncheckedThrow.throwAnyException(t); + } catch (IllegalAccessException e) { + // Impossible + Log.wtf(TAG, "IllegalAccessException while invoking " + method, e); + } catch (IllegalArgumentException e) { + // Impossible + Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e); + } catch (Throwable e) { + UncheckedThrow.throwAnyException(e); + } + } + }); + + // TODO handle primitive return values that would avoid NPE if unboxed + return null; + } +} diff --git a/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java b/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java new file mode 100644 index 000000000000..ac5f52676df4 --- /dev/null +++ b/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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.hardware.camera2.dispatch; + +import android.hardware.camera2.utils.UncheckedThrow; +import android.util.Log; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import static com.android.internal.util.Preconditions.*; + + +public class InvokeDispatcher<T> implements Dispatchable<T> { + + private static final String TAG = "InvocationSink"; + private final T mTarget; + + public InvokeDispatcher(T target) { + mTarget = checkNotNull(target, "target must not be null"); + } + + @Override + public Object dispatch(Method method, Object[] args) { + try { + return method.invoke(mTarget, args); + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + // Potential UB. Hopefully 't' is a runtime exception. + UncheckedThrow.throwAnyException(t); + } catch (IllegalAccessException e) { + // Impossible + Log.wtf(TAG, "IllegalAccessException while invoking " + method, e); + } catch (IllegalArgumentException e) { + // Impossible + Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e); + } + + // unreachable + return null; + } +} diff --git a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java new file mode 100644 index 000000000000..8296b7a915a4 --- /dev/null +++ b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2014 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.hardware.camera2.dispatch; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.hardware.camera2.utils.UncheckedThrow; + +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time). + * + * @param <T> destination dispatch type, methods will be looked up in the class of {@code T} + */ +public class MethodNameInvoker<T> { + + private final Dispatchable<T> mTarget; + private final Class<T> mTargetClass; + private final Method[] mTargetClassMethods; + private final ConcurrentHashMap<String, Method> mMethods = + new ConcurrentHashMap<>(); + + /** + * Create a new method name invoker. + * + * @param target destination dispatch type, invokes will be redirected to this dispatcher + * @param targetClass destination dispatch class, the invoked methods will be from this class + */ + public MethodNameInvoker(Dispatchable<T> target, Class<T> targetClass) { + mTargetClass = targetClass; + mTargetClassMethods = targetClass.getMethods(); + mTarget = target; + } + + /** + * Invoke a method by its name. + * + * <p>If more than one method exists in {@code targetClass}, the first method with the right + * number of arguments will be used, and later calls will all use that method.</p> + * + * @param methodName + * The name of the method, which will be matched 1:1 to the destination method + * @param params + * Variadic parameter list. + * @return + * The same kind of value that would normally be returned by calling {@code methodName} + * statically. + * + * @throws IllegalArgumentException if {@code methodName} does not exist on the target class + * @throws Throwable will rethrow anything that the target method would normally throw + */ + @SuppressWarnings("unchecked") + public <K> K invoke(String methodName, Object... params) { + checkNotNull(methodName, "methodName must not be null"); + + Method targetMethod = mMethods.get(methodName); + if (targetMethod == null) { + for (Method method : mTargetClassMethods) { + // TODO future: match types of params if possible + if (method.getName().equals(methodName) && + (params.length == method.getParameterTypes().length) ) { + targetMethod = method; + mMethods.put(methodName, targetMethod); + break; + } + } + + if (targetMethod == null) { + throw new IllegalArgumentException( + "Method " + methodName + " does not exist on class " + mTargetClass); + } + } + + try { + return (K) mTarget.dispatch(targetMethod, params); + } catch (Throwable e) { + UncheckedThrow.throwAnyException(e); + // unreachable + return null; + } + } +} diff --git a/core/java/android/hardware/camera2/dispatch/NullDispatcher.java b/core/java/android/hardware/camera2/dispatch/NullDispatcher.java new file mode 100644 index 000000000000..fada075cba67 --- /dev/null +++ b/core/java/android/hardware/camera2/dispatch/NullDispatcher.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 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.hardware.camera2.dispatch; + + +import java.lang.reflect.Method; + +/** + * Do nothing when dispatching; follows the null object pattern. + */ +public class NullDispatcher<T> implements Dispatchable<T> { + /** + * Create a dispatcher that does nothing when dispatched to. + */ + public NullDispatcher() { + } + + /** + * Do nothing; all parameters are ignored. + */ + @Override + public Object dispatch(Method method, Object[] args) { + return null; + } +} diff --git a/core/java/android/hardware/camera2/dispatch/package.html b/core/java/android/hardware/camera2/dispatch/package.html new file mode 100644 index 000000000000..783d0a1b54d5 --- /dev/null +++ b/core/java/android/hardware/camera2/dispatch/package.html @@ -0,0 +1,3 @@ +<body> +{@hide} +</body> diff --git a/core/java/android/hardware/camera2/impl/CallbackProxies.java b/core/java/android/hardware/camera2/impl/CallbackProxies.java index 9e4cb80b89f0..c9eecf10e3d3 100644 --- a/core/java/android/hardware/camera2/impl/CallbackProxies.java +++ b/core/java/android/hardware/camera2/impl/CallbackProxies.java @@ -15,17 +15,16 @@ */ package android.hardware.camera2.impl; -import android.os.Binder; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.dispatch.Dispatchable; +import android.hardware.camera2.dispatch.MethodNameInvoker; import android.view.Surface; -import java.util.concurrent.Executor; - import static com.android.internal.util.Preconditions.*; /** @@ -35,86 +34,164 @@ import static com.android.internal.util.Preconditions.*; * to use our own proxy mechanism.</p> */ public class CallbackProxies { + + // TODO: replace with codegen + + public static class DeviceStateCallbackProxy extends CameraDeviceImpl.StateCallbackKK { + private final MethodNameInvoker<CameraDeviceImpl.StateCallbackKK> mProxy; + + public DeviceStateCallbackProxy( + Dispatchable<CameraDeviceImpl.StateCallbackKK> dispatchTarget) { + dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null"); + mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.StateCallbackKK.class); + } + + @Override + public void onOpened(CameraDevice camera) { + mProxy.invoke("onOpened", camera); + } + + @Override + public void onDisconnected(CameraDevice camera) { + mProxy.invoke("onDisconnected", camera); + } + + @Override + public void onError(CameraDevice camera, int error) { + mProxy.invoke("onError", camera, error); + } + + @Override + public void onUnconfigured(CameraDevice camera) { + mProxy.invoke("onUnconfigured", camera); + } + + @Override + public void onActive(CameraDevice camera) { + mProxy.invoke("onActive", camera); + } + + @Override + public void onBusy(CameraDevice camera) { + mProxy.invoke("onBusy", camera); + } + + @Override + public void onClosed(CameraDevice camera) { + mProxy.invoke("onClosed", camera); + } + + @Override + public void onIdle(CameraDevice camera) { + mProxy.invoke("onIdle", camera); + } + } + + @SuppressWarnings("deprecation") + public static class DeviceCaptureCallbackProxy implements CameraDeviceImpl.CaptureCallback { + private final MethodNameInvoker<CameraDeviceImpl.CaptureCallback> mProxy; + + public DeviceCaptureCallbackProxy( + Dispatchable<CameraDeviceImpl.CaptureCallback> dispatchTarget) { + dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null"); + mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.CaptureCallback.class); + } + + @Override + public void onCaptureStarted(CameraDevice camera, + CaptureRequest request, long timestamp, long frameNumber) { + mProxy.invoke("onCaptureStarted", camera, request, timestamp, frameNumber); + } + + @Override + public void onCapturePartial(CameraDevice camera, + CaptureRequest request, CaptureResult result) { + mProxy.invoke("onCapturePartial", camera, request, result); + } + + @Override + public void onCaptureProgressed(CameraDevice camera, + CaptureRequest request, CaptureResult partialResult) { + mProxy.invoke("onCaptureProgressed", camera, request, partialResult); + } + + @Override + public void onCaptureCompleted(CameraDevice camera, + CaptureRequest request, TotalCaptureResult result) { + mProxy.invoke("onCaptureCompleted", camera, request, result); + } + + @Override + public void onCaptureFailed(CameraDevice camera, + CaptureRequest request, CaptureFailure failure) { + mProxy.invoke("onCaptureFailed", camera, request, failure); + } + + @Override + public void onCaptureSequenceCompleted(CameraDevice camera, + int sequenceId, long frameNumber) { + mProxy.invoke("onCaptureSequenceCompleted", camera, sequenceId, frameNumber); + } + + @Override + public void onCaptureSequenceAborted(CameraDevice camera, + int sequenceId) { + mProxy.invoke("onCaptureSequenceAborted", camera, sequenceId); + } + + @Override + public void onCaptureBufferLost(CameraDevice camera, + CaptureRequest request, Surface target, long frameNumber) { + mProxy.invoke("onCaptureBufferLost", camera, request, target, frameNumber); + } + + } + public static class SessionStateCallbackProxy extends CameraCaptureSession.StateCallback { - private final Executor mExecutor; - private final CameraCaptureSession.StateCallback mCallback; + private final MethodNameInvoker<CameraCaptureSession.StateCallback> mProxy; - public SessionStateCallbackProxy(Executor executor, - CameraCaptureSession.StateCallback callback) { - mExecutor = checkNotNull(executor, "executor must not be null"); - mCallback = checkNotNull(callback, "callback must not be null"); + public SessionStateCallbackProxy( + Dispatchable<CameraCaptureSession.StateCallback> dispatchTarget) { + dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null"); + mProxy = new MethodNameInvoker<>(dispatchTarget, + CameraCaptureSession.StateCallback.class); } @Override public void onConfigured(CameraCaptureSession session) { - final long ident = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onConfigured(session)); - } finally { - Binder.restoreCallingIdentity(ident); - } + mProxy.invoke("onConfigured", session); } @Override public void onConfigureFailed(CameraCaptureSession session) { - final long ident = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onConfigureFailed(session)); - } finally { - Binder.restoreCallingIdentity(ident); - } + mProxy.invoke("onConfigureFailed", session); } @Override public void onReady(CameraCaptureSession session) { - final long ident = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onReady(session)); - } finally { - Binder.restoreCallingIdentity(ident); - } + mProxy.invoke("onReady", session); } @Override public void onActive(CameraCaptureSession session) { - final long ident = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onActive(session)); - } finally { - Binder.restoreCallingIdentity(ident); - } + mProxy.invoke("onActive", session); } @Override public void onCaptureQueueEmpty(CameraCaptureSession session) { - final long ident = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onCaptureQueueEmpty(session)); - } finally { - Binder.restoreCallingIdentity(ident); - } + mProxy.invoke("onCaptureQueueEmpty", session); } @Override public void onClosed(CameraCaptureSession session) { - final long ident = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onClosed(session)); - } finally { - Binder.restoreCallingIdentity(ident); - } + mProxy.invoke("onClosed", session); } @Override public void onSurfacePrepared(CameraCaptureSession session, Surface surface) { - final long ident = Binder.clearCallingIdentity(); - try { - mExecutor.execute(() -> mCallback.onSurfacePrepared(session, surface)); - } finally { - Binder.restoreCallingIdentity(ident); - } + mProxy.invoke("onSurfacePrepared", session, surface); } } diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index f3f6c84a7e0b..8b8bbc34f7d2 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -20,18 +20,20 @@ import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.ICameraDeviceUser; +import android.hardware.camera2.dispatch.ArgumentReplacingDispatcher; +import android.hardware.camera2.dispatch.BroadcastDispatcher; +import android.hardware.camera2.dispatch.DuckTypingDispatcher; +import android.hardware.camera2.dispatch.HandlerDispatcher; +import android.hardware.camera2.dispatch.InvokeDispatcher; import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.utils.TaskDrainer; import android.hardware.camera2.utils.TaskSingleDrainer; -import android.os.Binder; import android.os.Handler; -import android.os.HandlerExecutor; import android.util.Log; import android.view.Surface; import java.util.Arrays; import java.util.List; -import java.util.concurrent.Executor; import static android.hardware.camera2.impl.CameraDeviceImpl.checkHandler; import static com.android.internal.util.Preconditions.*; @@ -49,11 +51,11 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession private final Surface mInput; /** * User-specified state callback, used for outgoing events; calls to this object will be - * automatically invoked via {@code mStateExecutor}. + * automatically {@link Handler#post(Runnable) posted} to {@code mStateHandler}. */ private final CameraCaptureSession.StateCallback mStateCallback; - /** User-specified state executor used for outgoing state callback events */ - private final Executor mStateExecutor; + /** User-specified state handler used for outgoing state callback events */ + private final Handler mStateHandler; /** Internal camera device; used to translate calls into existing deprecated API */ private final android.hardware.camera2.impl.CameraDeviceImpl mDeviceImpl; @@ -85,7 +87,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession * (e.g. no pending captures, no repeating requests, no flush).</p> */ CameraCaptureSessionImpl(int id, Surface input, - CameraCaptureSession.StateCallback callback, Executor stateExecutor, + CameraCaptureSession.StateCallback callback, Handler stateHandler, android.hardware.camera2.impl.CameraDeviceImpl deviceImpl, Handler deviceStateHandler, boolean configureSuccess) { if (callback == null) { @@ -96,8 +98,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession mIdString = String.format("Session %d: ", mId); mInput = input; - mStateExecutor = checkNotNull(stateExecutor, "stateExecutor must not be null"); - mStateCallback = createUserStateCallbackProxy(mStateExecutor, callback); + mStateHandler = checkHandler(stateHandler); + mStateCallback = createUserStateCallbackProxy(mStateHandler, callback); mDeviceHandler = checkNotNull(deviceStateHandler, "deviceStateHandler must not be null"); mDeviceImpl = checkNotNull(deviceImpl, "deviceImpl must not be null"); @@ -108,12 +110,12 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession * This ensures total ordering between CameraDevice.StateCallback and * CameraDeviceImpl.CaptureCallback events. */ - mSequenceDrainer = new TaskDrainer<>(new HandlerExecutor(mDeviceHandler), - new SequenceDrainListener(), /*name*/"seq"); - mIdleDrainer = new TaskSingleDrainer(new HandlerExecutor(mDeviceHandler), - new IdleDrainListener(), /*name*/"idle"); - mAbortDrainer = new TaskSingleDrainer(new HandlerExecutor(mDeviceHandler), - new AbortDrainListener(), /*name*/"abort"); + mSequenceDrainer = new TaskDrainer<>(mDeviceHandler, new SequenceDrainListener(), + /*name*/"seq"); + mIdleDrainer = new TaskSingleDrainer(mDeviceHandler, new IdleDrainListener(), + /*name*/"idle"); + mAbortDrainer = new TaskSingleDrainer(mDeviceHandler, new AbortDrainListener(), + /*name*/"abort"); // CameraDevice should call configureOutputs and have it finish before constructing us @@ -444,140 +446,114 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession } /** - * Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code executor}. + * Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code handler}. */ - private StateCallback createUserStateCallbackProxy(Executor executor, StateCallback callback) { - return new CallbackProxies.SessionStateCallbackProxy(executor, callback); + private StateCallback createUserStateCallbackProxy(Handler handler, StateCallback callback) { + InvokeDispatcher<StateCallback> userCallbackSink = new InvokeDispatcher<>(callback); + HandlerDispatcher<StateCallback> handlerPassthrough = + new HandlerDispatcher<>(userCallbackSink, handler); + + return new CallbackProxies.SessionStateCallbackProxy(handlerPassthrough); } /** * Forward callbacks from * CameraDeviceImpl.CaptureCallback to the CameraCaptureSession.CaptureCallback. * + * <p>In particular, all calls are automatically split to go both to our own + * internal callback, and to the user-specified callback (by transparently posting + * to the user-specified handler).</p> + * * <p>When a capture sequence finishes, update the pending checked sequences set.</p> */ @SuppressWarnings("deprecation") private CameraDeviceImpl.CaptureCallback createCaptureCallbackProxy( Handler handler, CaptureCallback callback) { - final Executor executor = (callback != null) ? CameraDeviceImpl.checkAndWrapHandler( - handler) : null; + CameraDeviceImpl.CaptureCallback localCallback = new CameraDeviceImpl.CaptureCallback() { - return new CameraDeviceImpl.CaptureCallback() { @Override public void onCaptureStarted(CameraDevice camera, CaptureRequest request, long timestamp, long frameNumber) { - if ((callback != null) && (executor != null)) { - final long ident = Binder.clearCallingIdentity(); - try { - executor.execute(() -> callback.onCaptureStarted( - CameraCaptureSessionImpl.this, request, timestamp, - frameNumber)); - } finally { - Binder.restoreCallingIdentity(ident); - } - } + // Do nothing } @Override public void onCapturePartial(CameraDevice camera, CaptureRequest request, android.hardware.camera2.CaptureResult result) { - if ((callback != null) && (executor != null)) { - final long ident = Binder.clearCallingIdentity(); - try { - executor.execute(() -> callback.onCapturePartial( - CameraCaptureSessionImpl.this, request, result)); - } finally { - Binder.restoreCallingIdentity(ident); - } - } + // Do nothing } @Override public void onCaptureProgressed(CameraDevice camera, CaptureRequest request, android.hardware.camera2.CaptureResult partialResult) { - if ((callback != null) && (executor != null)) { - final long ident = Binder.clearCallingIdentity(); - try { - executor.execute(() -> callback.onCaptureProgressed( - CameraCaptureSessionImpl.this, request, partialResult)); - } finally { - Binder.restoreCallingIdentity(ident); - } - } + // Do nothing } @Override public void onCaptureCompleted(CameraDevice camera, CaptureRequest request, android.hardware.camera2.TotalCaptureResult result) { - if ((callback != null) && (executor != null)) { - final long ident = Binder.clearCallingIdentity(); - try { - executor.execute(() -> callback.onCaptureCompleted( - CameraCaptureSessionImpl.this, request, result)); - } finally { - Binder.restoreCallingIdentity(ident); - } - } + // Do nothing } @Override public void onCaptureFailed(CameraDevice camera, CaptureRequest request, android.hardware.camera2.CaptureFailure failure) { - if ((callback != null) && (executor != null)) { - final long ident = Binder.clearCallingIdentity(); - try { - executor.execute(() -> callback.onCaptureFailed( - CameraCaptureSessionImpl.this, request, failure)); - } finally { - Binder.restoreCallingIdentity(ident); - } - } + // Do nothing } @Override public void onCaptureSequenceCompleted(CameraDevice camera, int sequenceId, long frameNumber) { - if ((callback != null) && (executor != null)) { - final long ident = Binder.clearCallingIdentity(); - try { - executor.execute(() -> callback.onCaptureSequenceCompleted( - CameraCaptureSessionImpl.this, sequenceId, frameNumber)); - } finally { - Binder.restoreCallingIdentity(ident); - } - } finishPendingSequence(sequenceId); } @Override public void onCaptureSequenceAborted(CameraDevice camera, int sequenceId) { - if ((callback != null) && (executor != null)) { - final long ident = Binder.clearCallingIdentity(); - try { - executor.execute(() -> callback.onCaptureSequenceAborted( - CameraCaptureSessionImpl.this, sequenceId)); - } finally { - Binder.restoreCallingIdentity(ident); - } - } finishPendingSequence(sequenceId); } @Override public void onCaptureBufferLost(CameraDevice camera, CaptureRequest request, Surface target, long frameNumber) { - if ((callback != null) && (executor != null)) { - final long ident = Binder.clearCallingIdentity(); - try { - executor.execute(() -> callback.onCaptureBufferLost( - CameraCaptureSessionImpl.this, request, target, frameNumber)); - } finally { - Binder.restoreCallingIdentity(ident); - } - } + // Do nothing } + }; + + /* + * Split the calls from the device callback into local callback and the following chain: + * - replace the first CameraDevice arg with a CameraCaptureSession + * - duck type from device callback to session callback + * - then forward the call to a handler + * - then finally invoke the destination method on the session callback object + */ + if (callback == null) { + // OK: API allows the user to not specify a callback, and the handler may + // also be null in that case. Collapse whole dispatch chain to only call the local + // callback + return localCallback; + } + + InvokeDispatcher<CameraDeviceImpl.CaptureCallback> localSink = + new InvokeDispatcher<>(localCallback); + + InvokeDispatcher<CaptureCallback> userCallbackSink = + new InvokeDispatcher<>(callback); + HandlerDispatcher<CaptureCallback> handlerPassthrough = + new HandlerDispatcher<>(userCallbackSink, handler); + DuckTypingDispatcher<CameraDeviceImpl.CaptureCallback, CaptureCallback> duckToSession + = new DuckTypingDispatcher<>(handlerPassthrough, CaptureCallback.class); + ArgumentReplacingDispatcher<CameraDeviceImpl.CaptureCallback, CameraCaptureSessionImpl> + replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession, + /*argumentIndex*/0, this); + + BroadcastDispatcher<CameraDeviceImpl.CaptureCallback> broadcaster = + new BroadcastDispatcher<CameraDeviceImpl.CaptureCallback>( + replaceDeviceWithSession, + localSink); + + return new CallbackProxies.DeviceCaptureCallbackProxy(broadcaster); } /** diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java index 4ee08bae84cb..06c2c25ab6bb 100644 --- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java @@ -33,7 +33,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.concurrent.Executor; import static com.android.internal.util.Preconditions.*; @@ -60,14 +59,14 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl * (e.g. no pending captures, no repeating requests, no flush).</p> */ CameraConstrainedHighSpeedCaptureSessionImpl(int id, - CameraCaptureSession.StateCallback callback, Executor stateExecutor, + CameraCaptureSession.StateCallback callback, Handler stateHandler, android.hardware.camera2.impl.CameraDeviceImpl deviceImpl, Handler deviceStateHandler, boolean configureSuccess, CameraCharacteristics characteristics) { mCharacteristics = characteristics; CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback); mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback, - stateExecutor, deviceImpl, deviceStateHandler, configureSuccess); + stateHandler, deviceImpl, deviceStateHandler, configureSuccess); } @Override diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index b328bb1726e9..511fa43a5441 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -35,10 +35,8 @@ import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.SubmitInfo; import android.hardware.camera2.utils.SurfaceUtils; -import android.os.Binder; import android.os.Build; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; @@ -60,7 +58,6 @@ import java.util.List; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.Executor; /** * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate @@ -504,9 +501,8 @@ public class CameraDeviceImpl extends CameraDevice for (Surface surface : outputs) { outConfigurations.add(new OutputConfiguration(surface)); } - createCaptureSessionInternal(null, outConfigurations, callback, - checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, - /*sessionParams*/ null); + createCaptureSessionInternal(null, outConfigurations, callback, handler, + /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null); } @Override @@ -521,7 +517,7 @@ public class CameraDeviceImpl extends CameraDevice // OutputConfiguration objects are immutable, but need to have our own array List<OutputConfiguration> currentOutputs = new ArrayList<>(outputConfigurations); - createCaptureSessionInternal(null, currentOutputs, callback, checkAndWrapHandler(handler), + createCaptureSessionInternal(null, currentOutputs, callback, handler, /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/null); } @@ -541,9 +537,8 @@ public class CameraDeviceImpl extends CameraDevice for (Surface surface : outputs) { outConfigurations.add(new OutputConfiguration(surface)); } - createCaptureSessionInternal(inputConfig, outConfigurations, callback, - checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, - /*sessionParams*/ null); + createCaptureSessionInternal(inputConfig, outConfigurations, callback, handler, + /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null); } @Override @@ -571,8 +566,8 @@ public class CameraDeviceImpl extends CameraDevice currentOutputs.add(new OutputConfiguration(output)); } createCaptureSessionInternal(inputConfig, currentOutputs, - callback, checkAndWrapHandler(handler), - /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null); + callback, handler, /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, + /*sessionParams*/ null); } @Override @@ -587,8 +582,7 @@ public class CameraDeviceImpl extends CameraDevice for (Surface surface : outputs) { outConfigurations.add(new OutputConfiguration(surface)); } - createCaptureSessionInternal(null, outConfigurations, callback, - checkAndWrapHandler(handler), + createCaptureSessionInternal(null, outConfigurations, callback, handler, /*operatingMode*/ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE, /*sessionParams*/ null); } @@ -603,8 +597,8 @@ public class CameraDeviceImpl extends CameraDevice for (OutputConfiguration output : outputs) { currentOutputs.add(new OutputConfiguration(output)); } - createCaptureSessionInternal(inputConfig, currentOutputs, callback, - checkAndWrapHandler(handler), operatingMode, /*sessionParams*/ null); + createCaptureSessionInternal(inputConfig, currentOutputs, callback, handler, operatingMode, + /*sessionParams*/ null); } @Override @@ -618,17 +612,14 @@ public class CameraDeviceImpl extends CameraDevice if (outputConfigs == null) { throw new IllegalArgumentException("Invalid output configurations"); } - if (config.getExecutor() == null) { - throw new IllegalArgumentException("Invalid executor"); - } createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs, - config.getStateCallback(), config.getExecutor(), config.getSessionType(), + config.getStateCallback(), config.getHandler(), config.getSessionType(), config.getSessionParameters()); } private void createCaptureSessionInternal(InputConfiguration inputConfig, List<OutputConfiguration> outputConfigurations, - CameraCaptureSession.StateCallback callback, Executor executor, + CameraCaptureSession.StateCallback callback, Handler handler, int operatingMode, CaptureRequest sessionParams) throws CameraAccessException { synchronized(mInterfaceLock) { if (DEBUG) { @@ -682,11 +673,12 @@ public class CameraDeviceImpl extends CameraDevice SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config); newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++, - callback, executor, this, mDeviceHandler, configureSuccess, + callback, handler, this, mDeviceHandler, configureSuccess, mCharacteristics); } else { newSession = new CameraCaptureSessionImpl(mNextSessionId++, input, - callback, executor, this, mDeviceHandler, configureSuccess); + callback, handler, this, mDeviceHandler, + configureSuccess); } // TODO: wait until current session closes, then create the new session @@ -971,12 +963,7 @@ public class CameraDeviceImpl extends CameraDevice } } }; - final long ident = Binder.clearCallingIdentity(); - try { - holder.getExecutor().execute(resultDispatch); - } finally { - Binder.restoreCallingIdentity(ident); - } + holder.getHandler().post(resultDispatch); } else { Log.w(TAG, String.format( "did not register callback to request %d", @@ -997,9 +984,9 @@ public class CameraDeviceImpl extends CameraDevice private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback, Handler handler, boolean repeating) throws CameraAccessException { - // Need a valid executor, or current thread needs to have a looper, if + // Need a valid handler, or current thread needs to have a looper, if // callback is valid - Executor executor = getExecutor(handler, callback); + handler = checkHandler(handler, callback); // Make sure that there all requests have at least 1 surface; all surfaces are non-null; // the surface isn't a physical stream surface for reprocessing request @@ -1053,7 +1040,7 @@ public class CameraDeviceImpl extends CameraDevice if (callback != null) { mCaptureCallbackMap.put(requestInfo.getRequestId(), new CaptureCallbackHolder( - callback, requestList, executor, repeating, mNextSessionId - 1)); + callback, requestList, handler, repeating, mNextSessionId - 1)); } else { if (DEBUG) { Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null"); @@ -1367,7 +1354,7 @@ public class CameraDeviceImpl extends CameraDevice private final boolean mRepeating; private final CaptureCallback mCallback; private final List<CaptureRequest> mRequestList; - private final Executor mExecutor; + private final Handler mHandler; private final int mSessionId; /** * <p>Determine if the callback holder is for a constrained high speed request list that @@ -1379,13 +1366,13 @@ public class CameraDeviceImpl extends CameraDevice private final boolean mHasBatchedOutputs; CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList, - Executor executor, boolean repeating, int sessionId) { - if (callback == null || executor == null) { + Handler handler, boolean repeating, int sessionId) { + if (callback == null || handler == null) { throw new UnsupportedOperationException( "Must have a valid handler and a valid callback"); } mRepeating = repeating; - mExecutor = executor; + mHandler = handler; mRequestList = new ArrayList<CaptureRequest>(requestList); mCallback = callback; mSessionId = sessionId; @@ -1438,8 +1425,8 @@ public class CameraDeviceImpl extends CameraDevice return getRequest(0); } - public Executor getExecutor() { - return mExecutor; + public Handler getHandler() { + return mHandler; } public int getSessionId() { @@ -1823,12 +1810,7 @@ public class CameraDeviceImpl extends CameraDevice } } }; - final long ident = Binder.clearCallingIdentity(); - try { - holder.getExecutor().execute(resultDispatch); - } finally { - Binder.restoreCallingIdentity(ident); - } + holder.getHandler().post(resultDispatch); } } } @@ -1879,7 +1861,7 @@ public class CameraDeviceImpl extends CameraDevice private void scheduleNotifyError(int code) { mInError = true; CameraDeviceImpl.this.mDeviceHandler.post(obtainRunnable( - CameraDeviceCallbacks::notifyError, this, code)); + CameraDeviceCallbacks::notifyError, this, code)); } private void notifyError(int code) { @@ -1947,41 +1929,36 @@ public class CameraDeviceImpl extends CameraDevice if (isClosed()) return; // Dispatch capture start notice - final long ident = Binder.clearCallingIdentity(); - try { - holder.getExecutor().execute( - new Runnable() { - @Override - public void run() { - if (!CameraDeviceImpl.this.isClosed()) { - final int subsequenceId = resultExtras.getSubsequenceId(); - final CaptureRequest request = holder.getRequest(subsequenceId); - - if (holder.hasBatchedOutputs()) { - // Send derived onCaptureStarted for requests within the - // batch - final Range<Integer> fpsRange = - request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE); - for (int i = 0; i < holder.getRequestCount(); i++) { - holder.getCallback().onCaptureStarted( - CameraDeviceImpl.this, - holder.getRequest(i), - timestamp - (subsequenceId - i) * - NANO_PER_SECOND/fpsRange.getUpper(), - frameNumber - (subsequenceId - i)); - } - } else { + holder.getHandler().post( + new Runnable() { + @Override + public void run() { + if (!CameraDeviceImpl.this.isClosed()) { + final int subsequenceId = resultExtras.getSubsequenceId(); + final CaptureRequest request = holder.getRequest(subsequenceId); + + if (holder.hasBatchedOutputs()) { + // Send derived onCaptureStarted for requests within the batch + final Range<Integer> fpsRange = + request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE); + for (int i = 0; i < holder.getRequestCount(); i++) { holder.getCallback().onCaptureStarted( CameraDeviceImpl.this, - holder.getRequest(resultExtras.getSubsequenceId()), - timestamp, frameNumber); + holder.getRequest(i), + timestamp - (subsequenceId - i) * + NANO_PER_SECOND/fpsRange.getUpper(), + frameNumber - (subsequenceId - i)); } + } else { + holder.getCallback().onCaptureStarted( + CameraDeviceImpl.this, + holder.getRequest(resultExtras.getSubsequenceId()), + timestamp, frameNumber); } } - }); - } finally { - Binder.restoreCallingIdentity(ident); - } + } + }); + } } @@ -2134,12 +2111,7 @@ public class CameraDeviceImpl extends CameraDevice finalResult = resultAsCapture; } - final long ident = Binder.clearCallingIdentity(); - try { - holder.getExecutor().execute(resultDispatch); - } finally { - Binder.restoreCallingIdentity(ident); - } + holder.getHandler().post(resultDispatch); // Collect the partials for a total result; or mark the frame as totally completed mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult, @@ -2235,12 +2207,7 @@ public class CameraDeviceImpl extends CameraDevice } }; // Dispatch the failure callback - final long ident = Binder.clearCallingIdentity(); - try { - holder.getExecutor().execute(failureDispatch); - } finally { - Binder.restoreCallingIdentity(ident); - } + holder.getHandler().post(failureDispatch); } } else { boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT); @@ -2280,12 +2247,7 @@ public class CameraDeviceImpl extends CameraDevice checkAndFireSequenceComplete(); // Dispatch the failure callback - final long ident = Binder.clearCallingIdentity(); - try { - holder.getExecutor().execute(failureDispatch); - } finally { - Binder.restoreCallingIdentity(ident); - } + holder.getHandler().post(failureDispatch); } } @@ -2293,37 +2255,6 @@ public class CameraDeviceImpl extends CameraDevice } // public class CameraDeviceCallbacks /** - * Instantiate a new Executor. - * - * <p>If the callback isn't null, check the handler and instantiate a new executor, - * otherwise instantiate a new executor in case handler is valid.</p> - */ - static <T> Executor getExecutor(Handler handler, T callback) { - if (callback != null) { - return checkAndWrapHandler(handler); - } - - if (handler != null) { - return new HandlerExecutor(handler); - } - - return null; - } - - /** - * Wrap Handler in Executor. - * - * <p> - * If handler is null, get the current thread's - * Looper to create a Executor with. If no looper exists, throw - * {@code IllegalArgumentException}. - * </p> - */ - static Executor checkAndWrapHandler(Handler handler) { - return new HandlerExecutor(checkHandler(handler)); - } - - /** * Default handler management. * * <p> diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java index 7bdb4a2f1339..a79a6c17f925 100644 --- a/core/java/android/hardware/camera2/params/SessionConfiguration.java +++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java @@ -17,10 +17,10 @@ package android.hardware.camera2.params; -import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.IntDef; +import android.os.Handler; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; @@ -31,7 +31,6 @@ import android.hardware.camera2.params.OutputConfiguration; import java.util.Collections; import java.util.List; import java.util.ArrayList; -import java.util.concurrent.Executor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -79,7 +78,7 @@ public final class SessionConfiguration { private List<OutputConfiguration> mOutputConfigurations; private CameraCaptureSession.StateCallback mStateCallback; private int mSessionType; - private Executor mExecutor = null; + private Handler mHandler = null; private InputConfiguration mInputConfig = null; private CaptureRequest mSessionParameters = null; @@ -88,9 +87,10 @@ public final class SessionConfiguration { * * @param sessionType The session type. * @param outputs A list of output configurations for the capture session. - * @param executor The executor which should be used to invoke the callback. In general it is - * recommended that camera operations are not done on the main (UI) thread. * @param cb A state callback interface implementation. + * @param handler The handler on which the callback will be invoked. If it is + * set to null, the callback will be invoked on the current thread's + * {@link android.os.Looper looper}. * * @see #SESSION_REGULAR * @see #SESSION_HIGH_SPEED @@ -101,12 +101,11 @@ public final class SessionConfiguration { */ public SessionConfiguration(@SessionMode int sessionType, @NonNull List<OutputConfiguration> outputs, - @NonNull @CallbackExecutor Executor executor, - @NonNull CameraCaptureSession.StateCallback cb) { + @NonNull CameraCaptureSession.StateCallback cb, @Nullable Handler handler) { mSessionType = sessionType; mOutputConfigurations = Collections.unmodifiableList(new ArrayList<>(outputs)); mStateCallback = cb; - mExecutor = executor; + mHandler = handler; } /** @@ -137,12 +136,14 @@ public final class SessionConfiguration { } /** - * Retrieve the {@link java.util.concurrent.Executor} for the capture session. + * Retrieve the {@link CameraCaptureSession.StateCallback} for the capture session. * - * @return The Executor on which the callback will be invoked. + * @return The handler on which the callback will be invoked. If it is + * set to null, the callback will be invoked on the current thread's + * {@link android.os.Looper looper}. */ - public Executor getExecutor() { - return mExecutor; + public Handler getHandler() { + return mHandler; } /** diff --git a/core/java/android/hardware/camera2/utils/TaskDrainer.java b/core/java/android/hardware/camera2/utils/TaskDrainer.java index e71f26a18792..ed30ff34afc8 100644 --- a/core/java/android/hardware/camera2/utils/TaskDrainer.java +++ b/core/java/android/hardware/camera2/utils/TaskDrainer.java @@ -15,11 +15,11 @@ */ package android.hardware.camera2.utils; +import android.os.Handler; import android.util.Log; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.Executor; import static com.android.internal.util.Preconditions.*; @@ -55,7 +55,7 @@ public class TaskDrainer<T> { private static final String TAG = "TaskDrainer"; private final boolean DEBUG = false; - private final Executor mExecutor; + private final Handler mHandler; private final DrainListener mListener; private final String mName; @@ -73,27 +73,28 @@ public class TaskDrainer<T> { /** * Create a new task drainer; {@code onDrained} callbacks will be posted to the listener - * via the {@code executor}. + * via the {@code handler}. * - * @param executor a non-{@code null} executor to use for listener execution + * @param handler a non-{@code null} handler to use to post runnables to * @param listener a non-{@code null} listener where {@code onDrained} will be called */ - public TaskDrainer(Executor executor, DrainListener listener) { - mExecutor = checkNotNull(executor, "executor must not be null"); + public TaskDrainer(Handler handler, DrainListener listener) { + mHandler = checkNotNull(handler, "handler must not be null"); mListener = checkNotNull(listener, "listener must not be null"); mName = null; } /** * Create a new task drainer; {@code onDrained} callbacks will be posted to the listener - * via the {@code executor}. + * via the {@code handler}. * - * @param executor a non-{@code null} executor to use for listener execution + * @param handler a non-{@code null} handler to use to post runnables to * @param listener a non-{@code null} listener where {@code onDrained} will be called * @param name an optional name used for debug logging */ - public TaskDrainer(Executor executor, DrainListener listener, String name) { - mExecutor = checkNotNull(executor, "executor must not be null"); + public TaskDrainer(Handler handler, DrainListener listener, String name) { + // XX: Probably don't need a handler at all here + mHandler = checkNotNull(handler, "handler must not be null"); mListener = checkNotNull(listener, "listener must not be null"); mName = name; } @@ -199,12 +200,15 @@ public class TaskDrainer<T> { } private void postDrained() { - mExecutor.execute(() -> { + mHandler.post(new Runnable() { + @Override + public void run() { if (DEBUG) { Log.v(TAG + "[" + mName + "]", "onDrained"); } mListener.onDrained(); + } }); } } diff --git a/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java b/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java index 9615450be447..f6272c9e6a66 100644 --- a/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java +++ b/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java @@ -16,8 +16,7 @@ package android.hardware.camera2.utils; import android.hardware.camera2.utils.TaskDrainer.DrainListener; - -import java.util.concurrent.Executor; +import android.os.Handler; /** * Keep track of a single concurrent task starting and finishing; @@ -39,25 +38,25 @@ public class TaskSingleDrainer { /** * Create a new task drainer; {@code onDrained} callbacks will be posted to the listener - * via the {@code executor}. + * via the {@code handler}. * - * @param executor a non-{@code null} executor to use for listener execution + * @param handler a non-{@code null} handler to use to post runnables to * @param listener a non-{@code null} listener where {@code onDrained} will be called */ - public TaskSingleDrainer(Executor executor, DrainListener listener) { - mTaskDrainer = new TaskDrainer<>(executor, listener); + public TaskSingleDrainer(Handler handler, DrainListener listener) { + mTaskDrainer = new TaskDrainer<>(handler, listener); } /** * Create a new task drainer; {@code onDrained} callbacks will be posted to the listener - * via the {@code executor}. + * via the {@code handler}. * - * @param executor a non-{@code null} executor to use for listener execution + * @param handler a non-{@code null} handler to use to post runnables to * @param listener a non-{@code null} listener where {@code onDrained} will be called * @param name an optional name used for debug logging */ - public TaskSingleDrainer(Executor executor, DrainListener listener, String name) { - mTaskDrainer = new TaskDrainer<>(executor, listener, name); + public TaskSingleDrainer(Handler handler, DrainListener listener, String name) { + mTaskDrainer = new TaskDrainer<>(handler, listener, name); } /** diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index f468942cc951..504f840af5bf 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -23,6 +23,7 @@ import android.util.IntArray; import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; +import android.view.SurfaceControl; /** * Display manager local system service interface. @@ -115,7 +116,7 @@ public abstract class DisplayManagerInternal { * Called by the window manager to perform traversals while holding a * surface flinger transaction. */ - public abstract void performTraversalInTransactionFromWindowManager(); + public abstract void performTraversal(SurfaceControl.Transaction t); /** * Tells the display manager about properties of the display that depend on the windows on it. diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index b3bf092aeffe..b4c8a5e504bc 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -20,6 +20,8 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; +import static java.lang.annotation.RetentionPolicy.SOURCE; + import android.annotation.CallSuper; import android.annotation.DrawableRes; import android.annotation.IntDef; @@ -239,19 +241,89 @@ public class InputMethodService extends AbstractInputMethodService { static final boolean DEBUG = false; /** - * The back button will close the input window. + * Allows the system to optimize the back button affordance based on the presence of software + * keyboard. + * + * <p>For instance, on devices that have navigation bar and software-rendered back button, the + * system may use a different icon while {@link #isInputViewShown()} returns {@code true}, to + * indicate that the back button has "dismiss" affordance.</p> + * + * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to + * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default + * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does + * not take this mode into account.</p> + * + * <p>For API level {@link android.os.Build.VERSION_CODES#O_MR1} and lower devices, this is the + * only mode you can safely specify without worrying about the compatibility.</p> + * + * @see #setBackDisposition(int) */ - public static final int BACK_DISPOSITION_DEFAULT = 0; // based on window + public static final int BACK_DISPOSITION_DEFAULT = 0; /** - * This input method will not consume the back key. + * Deprecated flag. + * + * <p>To avoid compatibility issues, IME developers should not use this flag.</p> + * + * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is + * handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On + * {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior + * of this mode had not been well defined. Most likely the end result would be the + * same as {@link #BACK_DISPOSITION_DEFAULT}. Either way it is not recommended to + * use this mode + * @see #setBackDisposition(int) */ - public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // back + @Deprecated + public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; /** - * This input method will consume the back key. + * Deprecated flag. + * + * <p>To avoid compatibility issues, IME developers should not use this flag.</p> + * + * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is + * handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On + * {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior + * of this mode had not been well defined. In AOSP implementation running on devices + * that have navigation bar, specifying this flag could change the software back + * button to "Dismiss" icon no matter whether the software keyboard is shown or not, + * but there would be no easy way to restore the icon state even after IME lost the + * connection to the application. To avoid user confusions, do not specify this mode + * anyway + * @see #setBackDisposition(int) */ - public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // down + @Deprecated + public static final int BACK_DISPOSITION_WILL_DISMISS = 2; + + /** + * Asks the system to not adjust the back button affordance even when the software keyboard is + * shown. + * + * <p>This mode is useful for UI modes where IME's main soft input window is used for some + * supplemental UI, such as floating candidate window for languages such as Chinese and + * Japanese, where users expect the back button is, or at least looks to be, handled by the + * target application rather than the UI shown by the IME even while {@link #isInputViewShown()} + * returns {@code true}.</p> + * + * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to + * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default + * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does + * not take this mode into account.</p> + * + * @see #setBackDisposition(int) + */ + public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3; + + /** + * Enum flag to be used for {@link #setBackDisposition(int)}. + * + * @hide + */ + @Retention(SOURCE) + @IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS, + BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING}, + prefix = "BACK_DISPOSITION_") + public @interface BackDispositionMode {} /** * @hide @@ -267,7 +339,7 @@ public class InputMethodService extends AbstractInputMethodService { // Min and max values for back disposition. private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT; - private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_WILL_DISMISS; + private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING; InputMethodManager mImm; @@ -331,6 +403,8 @@ public class InputMethodService extends AbstractInputMethodService { boolean mIsInputViewShown; int mStatusIcon; + + @BackDispositionMode int mBackDisposition; /** @@ -1015,8 +1089,19 @@ public class InputMethodService extends AbstractInputMethodService { public Dialog getWindow() { return mWindow; } - - public void setBackDisposition(int disposition) { + + /** + * Sets the disposition mode that indicates the expected affordance for the back button. + * + * <p>Keep in mind that specifying this flag does not change the the default behavior of + * {@link #onKeyDown(int, KeyEvent)}. It is IME developers' responsibility for making sure that + * their custom implementation of {@link #onKeyDown(int, KeyEvent)} is consistent with the mode + * specified to this API.</p> + * + * @see #getBackDisposition() + * @param disposition disposition mode to be set + */ + public void setBackDisposition(@BackDispositionMode int disposition) { if (disposition == mBackDisposition) { return; } @@ -1029,6 +1114,13 @@ public class InputMethodService extends AbstractInputMethodService { mBackDisposition); } + /** + * Retrieves the current disposition mode that indicates the expected back button affordance. + * + * @see #setBackDisposition(int) + * @return currently selected disposition mode + */ + @BackDispositionMode public int getBackDisposition() { return mBackDisposition; } @@ -1894,7 +1986,6 @@ public class InputMethodService extends AbstractInputMethodService { mInputStarted = false; mStartedInputConnection = null; mCurCompletions = null; - mBackDisposition = BACK_DISPOSITION_DEFAULT; } void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) { @@ -2096,25 +2187,31 @@ public class InputMethodService extends AbstractInputMethodService { return mExtractEditText; } + /** - * Override this to intercept key down events before they are processed by the - * application. If you return true, the application will not - * process the event itself. If you return false, the normal application processing - * will occur as if the IME had not seen the event at all. - * - * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK - * KeyEvent.KEYCODE_BACK} if the IME is currently shown, to - * possibly hide it when the key goes up (if not canceled or long pressed). In - * addition, in fullscreen mode only, it will consume DPAD movement - * events to move the cursor in the extracted text view, not allowing - * them to perform navigation in the underlying application. + * Called back when a {@link KeyEvent} is forwarded from the target application. + * + * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK} if the IME is + * currently shown , to possibly hide it when the key goes up (if not canceled or long pressed). + * In addition, in fullscreen mode only, it will consume DPAD movement events to move the cursor + * in the extracted text view, not allowing them to perform navigation in the underlying + * application.</p> + * + * <p>The default implementation does not take flags specified to + * {@link #setBackDisposition(int)} into account, even on API version + * {@link android.os.Build.VERSION_CODES#P} and later devices. IME developers are responsible + * for making sure that their special handling for {@link KeyEvent#KEYCODE_BACK} are consistent + * with the flag they specified to {@link #setBackDisposition(int)}.</p> + * + * @param keyCode The value in {@code event.getKeyCode()} + * @param event Description of the key event + * + * @return {@code true} if the event is consumed by the IME and the application no longer needs + * to consume it. Return {@code false} when the event should be handled as if the IME + * had not seen the event at all. */ public boolean onKeyDown(int keyCode, KeyEvent event) { - if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - if (mBackDisposition == BACK_DISPOSITION_WILL_NOT_DISMISS) { - return false; - } final ExtractEditText eet = getExtractEditTextIfVisible(); if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) { return true; diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java index 2bb43bd36be3..e84f91314386 100644 --- a/core/java/android/metrics/LogMaker.java +++ b/core/java/android/metrics/LogMaker.java @@ -103,7 +103,7 @@ public class LogMaker { * @hide // TODO Expose in the future? Too late for O. */ public LogMaker setLatency(long milliseconds) { - entries.put(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, milliseconds); + entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS, milliseconds); return this; } diff --git a/core/java/android/net/INetdEventCallback.aidl b/core/java/android/net/INetdEventCallback.aidl index 1fd9423b6128..1e75bf461a70 100644 --- a/core/java/android/net/INetdEventCallback.aidl +++ b/core/java/android/net/INetdEventCallback.aidl @@ -20,8 +20,9 @@ package android.net; oneway interface INetdEventCallback { // Possible addNetdEventCallback callers. - const int CALLBACK_CALLER_DEVICE_POLICY = 0; - const int CALLBACK_CALLER_NETWORK_WATCHLIST = 1; + const int CALLBACK_CALLER_CONNECTIVITY_SERVICE = 0; + const int CALLBACK_CALLER_DEVICE_POLICY = 1; + const int CALLBACK_CALLER_NETWORK_WATCHLIST = 2; /** * Reports a single DNS lookup function call. @@ -39,6 +40,18 @@ oneway interface INetdEventCallback { int uid); /** + * Represents a private DNS validation success or failure. + * This method must not block or perform long-running operations. + * + * @param netId the ID of the network the validation was performed on. + * @param ipAddress the IP address for which validation was performed. + * @param hostname the hostname for which validation was performed. + * @param validated whether or not validation was successful. + */ + void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, + boolean validated); + + /** * Reports a single connect library call. * This method must not block or perform long-running operations. * diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 29b7931bf7c7..2b5cece4bb35 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3727,7 +3727,7 @@ public final class Settings { public static final Validator SOUND_EFFECTS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR; /** - * Whether the haptic feedback (long presses, ...) are enabled. The value is + * Whether haptic feedback (Vibrate on tap) is enabled. The value is * boolean (1 or 0). */ public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled"; @@ -10271,31 +10271,6 @@ public final class Settings { "battery_saver_device_specific_constants"; /** - * Battery anomaly detection specific settings - * This is encoded as a key=value list, separated by commas. - * wakeup_blacklisted_tags is a string, encoded as a set of tags, encoded via - * {@link Uri#encode(String)}, separated by colons. Ex: - * - * "anomaly_detection_enabled=true,wakelock_threshold=2000,wakeup_alarm_enabled=true," - * "wakeup_alarm_threshold=10,wakeup_blacklisted_tags=tag1:tag2:with%2Ccomma:with%3Acolon" - * - * The following keys are supported: - * - * <pre> - * anomaly_detection_enabled (boolean) - * wakelock_enabled (boolean) - * wakelock_threshold (long) - * wakeup_alarm_enabled (boolean) - * wakeup_alarm_threshold (long) - * wakeup_blacklisted_tags (string) - * bluetooth_scan_enabled (boolean) - * bluetooth_scan_threshold (long) - * </pre> - * @hide - */ - public static final String ANOMALY_DETECTION_CONSTANTS = "anomaly_detection_constants"; - - /** * Battery tip specific settings * This is encoded as a key=value list, separated by commas. Ex: * @@ -10324,6 +10299,31 @@ public final class Settings { public static final String BATTERY_TIP_CONSTANTS = "battery_tip_constants"; /** + * Battery anomaly detection specific settings + * This is encoded as a key=value list, separated by commas. + * wakeup_blacklisted_tags is a string, encoded as a set of tags, encoded via + * {@link Uri#encode(String)}, separated by colons. Ex: + * + * "anomaly_detection_enabled=true,wakelock_threshold=2000,wakeup_alarm_enabled=true," + * "wakeup_alarm_threshold=10,wakeup_blacklisted_tags=tag1:tag2:with%2Ccomma:with%3Acolon" + * + * The following keys are supported: + * + * <pre> + * anomaly_detection_enabled (boolean) + * wakelock_enabled (boolean) + * wakelock_threshold (long) + * wakeup_alarm_enabled (boolean) + * wakeup_alarm_threshold (long) + * wakeup_blacklisted_tags (string) + * bluetooth_scan_enabled (boolean) + * bluetooth_scan_threshold (long) + * </pre> + * @hide + */ + public static final String ANOMALY_DETECTION_CONSTANTS = "anomaly_detection_constants"; + + /** * An integer to show the version of the anomaly config. Ex: 1, which means * current version is 1. * @hide @@ -10378,6 +10378,17 @@ public final class Settings { public static final String SYS_UIDCPUPOWER = "sys_uidcpupower"; /** + * traced global setting. This controls weather the deamons: traced and + * traced_probes run. This links the sys.traced system property. + * The following values are supported: + * 0 -> traced and traced_probes are disabled + * 1 -> traced and traced_probes are enabled + * Any other value defaults to disabled. + * @hide + */ + public static final String SYS_TRACED = "sys_traced"; + + /** * An integer to reduce the FPS by this factor. Only for experiments. Need to reboot the * device for this setting to take full effect. * @@ -10598,7 +10609,7 @@ public final class Settings { * Default: 1 * @hide */ - public static final java.lang.String APP_STANDBY_ENABLED = "app_standby_enabled"; + public static final String APP_STANDBY_ENABLED = "app_standby_enabled"; /** * Whether or not app auto restriction is enabled. When it is enabled, settings app will @@ -10609,7 +10620,7 @@ public final class Settings { * * @hide */ - public static final java.lang.String APP_AUTO_RESTRICTION_ENABLED = + public static final String APP_AUTO_RESTRICTION_ENABLED = "app_auto_restriction_enabled"; private static final Validator APP_AUTO_RESTRICTION_ENABLED_VALIDATOR = diff --git a/core/java/android/se/omapi/Session.java b/core/java/android/se/omapi/Session.java index 19a018ee01bb..3d8b74b51c4c 100644 --- a/core/java/android/se/omapi/Session.java +++ b/core/java/android/se/omapi/Session.java @@ -301,12 +301,6 @@ public class Session { * provide a new logical channel. */ public @Nullable Channel openLogicalChannel(byte[] aid, byte p2) throws IOException { - - if ((mReader.getName().startsWith("SIM")) && (aid == null)) { - Log.e(TAG, "NULL AID not supported on " + mReader.getName()); - return null; - } - if (!mService.isConnected()) { throw new IllegalStateException("service not connected to system"); } diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java index 4580c47ac3c3..00f54e16863d 100644 --- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java +++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java @@ -18,12 +18,14 @@ package android.security.keystore.recovery; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.os.BadParcelableException; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.util.Preconditions; import java.security.cert.CertPath; +import java.security.cert.CertificateException; import java.util.List; /** @@ -54,7 +56,7 @@ public final class KeyChainSnapshot implements Parcelable { private long mCounterId = DEFAULT_COUNTER_ID; private byte[] mServerParams; private byte[] mPublicKey; // The raw public key bytes used - private CertPath mCertPath; // The certificate path including the intermediate certificates + private RecoveryCertPath mCertPath; // The cert path including necessary intermediate certs private List<KeyChainProtectionParams> mKeyChainProtectionParams; private List<WrappedApplicationKey> mEntryRecoveryData; private byte[] mEncryptedRecoveryKeyBlob; @@ -127,7 +129,17 @@ public final class KeyChainSnapshot implements Parcelable { */ // TODO: Change to @NonNull public CertPath getTrustedHardwareCertPath() { - return mCertPath; + if (mCertPath == null) { + return null; + } else { + try { + return mCertPath.getCertPath(); + } catch (CertificateException e) { + // Rethrow an unchecked exception as it should not happen. If such an issue exists, + // an exception should have been thrown during service initialization. + throw new BadParcelableException(e); + } + } } /** @@ -232,11 +244,17 @@ public final class KeyChainSnapshot implements Parcelable { * contain a certificate of the trusted hardware public key and any necessary intermediate * certificates. * - * @param certPath The public key + * @param certPath The certificate path + * @throws CertificateException if the given certificate path cannot be encoded properly * @return This builder. */ - public Builder setTrustedHardwareCertPath(CertPath certPath) { - mInstance.mCertPath = certPath; + public Builder setTrustedHardwareCertPath(CertPath certPath) throws CertificateException { + // TODO: Make it NonNull when the caller code is all updated + if (certPath == null) { + mInstance.mCertPath = null; + } else { + mInstance.mCertPath = RecoveryCertPath.createRecoveryCertPath(certPath); + } return this; } @@ -302,6 +320,7 @@ public final class KeyChainSnapshot implements Parcelable { out.writeLong(mCounterId); out.writeByteArray(mServerParams); out.writeByteArray(mPublicKey); + out.writeTypedObject(mCertPath, /* no flags */ 0); } /** @@ -316,6 +335,7 @@ public final class KeyChainSnapshot implements Parcelable { mCounterId = in.readLong(); mServerParams = in.createByteArray(); mPublicKey = in.createByteArray(); + mCertPath = in.readTypedObject(RecoveryCertPath.CREATOR); } @Override diff --git a/core/java/android/util/KeyValueSettingObserver.java b/core/java/android/util/KeyValueSettingObserver.java new file mode 100644 index 000000000000..9fca8b2cfab2 --- /dev/null +++ b/core/java/android/util/KeyValueSettingObserver.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +import android.content.ContentResolver; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; + +/** + * Abstract class for observing changes to a specified setting stored as a comma-separated key value + * list of parameters. Registers and unregisters a {@link ContentObserver} and handles updates when + * the setting changes. + * + * <p>Subclasses should pass in the relevant setting's {@link Uri} in the constructor and implement + * {@link #update(KeyValueListParser)} to receive updates when the value changes. + * Calls to {@link #update(KeyValueListParser)} only trigger after calling {@link + * #start()}. + * + * <p>To get the most up-to-date parameter values, first call {@link #start()} before accessing the + * values to start observing changes, and then call {@link #stop()} once finished. + * + * @hide + */ +public abstract class KeyValueSettingObserver { + private static final String TAG = "KeyValueSettingObserver"; + + private final KeyValueListParser mParser = new KeyValueListParser(','); + + private final ContentObserver mObserver; + private final ContentResolver mResolver; + private final Uri mSettingUri; + + public KeyValueSettingObserver(Handler handler, ContentResolver resolver, + Uri uri) { + mObserver = new SettingObserver(handler); + mResolver = resolver; + mSettingUri = uri; + } + + /** Starts observing changes for the setting. Pair with {@link #stop()}. */ + public void start() { + mResolver.registerContentObserver(mSettingUri, false, mObserver); + setParserValue(); + update(mParser); + } + + /** Stops observing changes for the setting. */ + public void stop() { + mResolver.unregisterContentObserver(mObserver); + } + + /** + * Returns the {@link String} representation of the setting. Subclasses should implement this + * for their setting. + */ + public abstract String getSettingValue(ContentResolver resolver); + + /** Updates the parser with the current setting value. */ + private void setParserValue() { + String setting = getSettingValue(mResolver); + try { + mParser.setString(setting); + } catch (IllegalArgumentException e) { + Slog.e(TAG, "Malformed setting: " + setting); + } + } + + /** Subclasses should implement this to update references to their parameters. */ + public abstract void update(KeyValueListParser parser); + + private class SettingObserver extends ContentObserver { + private SettingObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange) { + setParserValue(); + update(mParser); + } + } +} diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index 5607b1134e5b..89684ca46003 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -51,4 +51,12 @@ interface IRecentsAnimationController { * and then enable it mid-animation to start receiving touch events. */ void setInputConsumerEnabled(boolean enabled); + + /** + * Informs the system whether the animation targets passed into + * IRecentsAnimationRunner.onAnimationStart are currently behind the system bars. If they are, + * they can control the SystemUI flags, otherwise the SystemUI flags from home activity will be + * taken. + */ + void setAnimationTargetsBehindSystemBars(boolean behindSystemBars); } diff --git a/core/java/android/view/RecordingCanvas.java b/core/java/android/view/RecordingCanvas.java index fc7d828de12e..f7a41ffa67e5 100644 --- a/core/java/android/view/RecordingCanvas.java +++ b/core/java/android/view/RecordingCanvas.java @@ -474,8 +474,7 @@ public class RecordingCanvas extends Canvas { } nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount, - x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */, - 0 /* measured text offset */); + x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */); } @Override @@ -506,19 +505,16 @@ public class RecordingCanvas extends Canvas { char[] buf = TemporaryBuffer.obtain(contextLen); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); long measuredTextPtr = 0; - int measuredTextOffset = 0; if (text instanceof PrecomputedText) { PrecomputedText mt = (PrecomputedText) text; int paraIndex = mt.findParaIndex(start); if (end <= mt.getParagraphEnd(paraIndex)) { // Only support if the target is in the same paragraph. measuredTextPtr = mt.getMeasuredParagraph(paraIndex).getNativePtr(); - measuredTextOffset = start - mt.getParagraphStart(paraIndex); } } nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len, - 0, contextLen, x, y, isRtl, paint.getNativeInstance(), - measuredTextPtr, measuredTextOffset); + 0, contextLen, x, y, isRtl, paint.getNativeInstance(), measuredTextPtr); TemporaryBuffer.recycle(buf); } } @@ -641,7 +637,7 @@ public class RecordingCanvas extends Canvas { @FastNative private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, - long nativePrecomputedText, int measuredTextOffset); + long nativePrecomputedText); @FastNative private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java index 8def43512e51..d2240e1f2775 100644 --- a/core/java/android/view/RemoteAnimationDefinition.java +++ b/core/java/android/view/RemoteAnimationDefinition.java @@ -16,10 +16,14 @@ package android.view; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; + import android.annotation.Nullable; +import android.app.WindowConfiguration; +import android.app.WindowConfiguration.ActivityType; import android.os.Parcel; import android.os.Parcelable; -import android.util.ArrayMap; +import android.util.ArraySet; import android.util.SparseArray; import android.view.WindowManager.TransitionType; @@ -30,7 +34,7 @@ import android.view.WindowManager.TransitionType; */ public class RemoteAnimationDefinition implements Parcelable { - private final SparseArray<RemoteAnimationAdapter> mTransitionAnimationMap; + private final SparseArray<RemoteAnimationAdapterEntry> mTransitionAnimationMap; public RemoteAnimationDefinition() { mTransitionAnimationMap = new SparseArray<>(); @@ -40,34 +44,70 @@ public class RemoteAnimationDefinition implements Parcelable { * Registers a remote animation for a specific transition. * * @param transition The transition type. Must be one of WindowManager.TRANSIT_* values. + * @param activityTypeFilter The remote animation only runs if an activity with type of this + * parameter is involved in the transition. + * @param adapter The adapter that described how to run the remote animation. + */ + public void addRemoteAnimation(@TransitionType int transition, + @ActivityType int activityTypeFilter, RemoteAnimationAdapter adapter) { + mTransitionAnimationMap.put(transition, + new RemoteAnimationAdapterEntry(adapter, activityTypeFilter)); + } + + /** + * Registers a remote animation for a specific transition without defining an activity type + * filter. + * + * @param transition The transition type. Must be one of WindowManager.TRANSIT_* values. * @param adapter The adapter that described how to run the remote animation. */ public void addRemoteAnimation(@TransitionType int transition, RemoteAnimationAdapter adapter) { - mTransitionAnimationMap.put(transition, adapter); + addRemoteAnimation(transition, ACTIVITY_TYPE_UNDEFINED, adapter); } /** * Checks whether a remote animation for specific transition is defined. * * @param transition The transition type. Must be one of WindowManager.TRANSIT_* values. + * @param activityTypes The set of activity types of activities that are involved in the + * transition. Will be used for filtering. * @return Whether this definition has defined a remote animation for the specified transition. */ - public boolean hasTransition(@TransitionType int transition) { - return mTransitionAnimationMap.get(transition) != null; + public boolean hasTransition(@TransitionType int transition, ArraySet<Integer> activityTypes) { + return getAdapter(transition, activityTypes) != null; } /** * Retrieves the remote animation for a specific transition. * * @param transition The transition type. Must be one of WindowManager.TRANSIT_* values. + * @param activityTypes The set of activity types of activities that are involved in the + * transition. Will be used for filtering. * @return The remote animation adapter for the specified transition. */ - public @Nullable RemoteAnimationAdapter getAdapter(@TransitionType int transition) { - return mTransitionAnimationMap.get(transition); + public @Nullable RemoteAnimationAdapter getAdapter(@TransitionType int transition, + ArraySet<Integer> activityTypes) { + final RemoteAnimationAdapterEntry entry = mTransitionAnimationMap.get(transition); + if (entry == null) { + return null; + } + if (entry.activityTypeFilter == ACTIVITY_TYPE_UNDEFINED + || activityTypes.contains(entry.activityTypeFilter)) { + return entry.adapter; + } else { + return null; + } } public RemoteAnimationDefinition(Parcel in) { - mTransitionAnimationMap = in.readSparseArray(null /* loader */); + final int size = in.readInt(); + mTransitionAnimationMap = new SparseArray<>(size); + for (int i = 0; i < size; i++) { + final int transition = in.readInt(); + final RemoteAnimationAdapterEntry entry = in.readTypedObject( + RemoteAnimationAdapterEntry.CREATOR); + mTransitionAnimationMap.put(transition, entry); + } } /** @@ -76,7 +116,7 @@ public class RemoteAnimationDefinition implements Parcelable { */ public void setCallingPid(int pid) { for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) { - mTransitionAnimationMap.valueAt(i).setCallingPid(pid); + mTransitionAnimationMap.valueAt(i).adapter.setCallingPid(pid); } } @@ -87,7 +127,12 @@ public class RemoteAnimationDefinition implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeSparseArray((SparseArray) mTransitionAnimationMap); + final int size = mTransitionAnimationMap.size(); + dest.writeInt(size); + for (int i = 0; i < size; i++) { + dest.writeInt(mTransitionAnimationMap.keyAt(i)); + dest.writeTypedObject(mTransitionAnimationMap.valueAt(i), flags); + } } public static final Creator<RemoteAnimationDefinition> CREATOR = @@ -100,4 +145,50 @@ public class RemoteAnimationDefinition implements Parcelable { return new RemoteAnimationDefinition[size]; } }; + + private static class RemoteAnimationAdapterEntry implements Parcelable { + + final RemoteAnimationAdapter adapter; + + /** + * Only run the transition if one of the activities matches the filter. + * {@link WindowConfiguration.ACTIVITY_TYPE_UNDEFINED} means no filter + */ + @ActivityType final int activityTypeFilter; + + RemoteAnimationAdapterEntry(RemoteAnimationAdapter adapter, int activityTypeFilter) { + this.adapter = adapter; + this.activityTypeFilter = activityTypeFilter; + } + + private RemoteAnimationAdapterEntry(Parcel in) { + adapter = in.readParcelable(RemoteAnimationAdapter.class.getClassLoader()); + activityTypeFilter = in.readInt(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(adapter, flags); + dest.writeInt(activityTypeFilter); + } + + @Override + public int describeContents() { + return 0; + } + + private static final Creator<RemoteAnimationAdapterEntry> CREATOR + = new Creator<RemoteAnimationAdapterEntry>() { + + @Override + public RemoteAnimationAdapterEntry createFromParcel(Parcel in) { + return new RemoteAnimationAdapterEntry(in); + } + + @Override + public RemoteAnimationAdapterEntry[] newArray(int size) { + return new RemoteAnimationAdapterEntry[size]; + } + }; + } } diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java index 75cdd49fccab..5b2cc81756c1 100644 --- a/core/java/android/view/RemoteAnimationTarget.java +++ b/core/java/android/view/RemoteAnimationTarget.java @@ -16,13 +16,26 @@ package android.view; +import static android.app.RemoteAnimationTargetProto.CLIP_RECT; +import static android.app.RemoteAnimationTargetProto.CONTENT_INSETS; +import static android.app.RemoteAnimationTargetProto.IS_TRANSLUCENT; +import static android.app.RemoteAnimationTargetProto.LEASH; +import static android.app.RemoteAnimationTargetProto.MODE; +import static android.app.RemoteAnimationTargetProto.POSITION; +import static android.app.RemoteAnimationTargetProto.PREFIX_ORDER_INDEX; +import static android.app.RemoteAnimationTargetProto.SOURCE_CONTAINER_BOUNDS; +import static android.app.RemoteAnimationTargetProto.TASK_ID; +import static android.app.RemoteAnimationTargetProto.WINDOW_CONFIGURATION; + import android.annotation.IntDef; import android.app.WindowConfiguration; import android.graphics.Point; import android.graphics.Rect; import android.os.Parcel; import android.os.Parcelable; +import android.util.proto.ProtoOutputStream; +import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -164,6 +177,35 @@ public class RemoteAnimationTarget implements Parcelable { dest.writeBoolean(isNotInRecents); } + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("mode="); pw.print(mode); + pw.print(" taskId="); pw.print(taskId); + pw.print(" isTranslucent="); pw.print(isTranslucent); + pw.print(" clipRect="); clipRect.printShortString(pw); + pw.print(" contentInsets="); contentInsets.printShortString(pw); + pw.print(" prefixOrderIndex="); pw.print(prefixOrderIndex); + pw.print(" position="); position.printShortString(pw); + pw.print(" sourceContainerBounds="); sourceContainerBounds.printShortString(pw); + pw.println(); + pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration); + pw.print(prefix); pw.print("leash="); pw.println(leash); + } + + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(TASK_ID, taskId); + proto.write(MODE, mode); + leash.writeToProto(proto, LEASH); + proto.write(IS_TRANSLUCENT, isTranslucent); + clipRect.writeToProto(proto, CLIP_RECT); + contentInsets.writeToProto(proto, CONTENT_INSETS); + proto.write(PREFIX_ORDER_INDEX, prefixOrderIndex); + position.writeToProto(proto, POSITION); + sourceContainerBounds.writeToProto(proto, SOURCE_CONTAINER_BOUNDS); + windowConfiguration.writeToProto(proto, WINDOW_CONFIGURATION); + proto.end(token); + } + public static final Creator<RemoteAnimationTarget> CREATOR = new Creator<RemoteAnimationTarget>() { public RemoteAnimationTarget createFromParcel(Parcel in) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index bf0e2ebf6deb..b624870deb9b 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6546,7 +6546,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } finally { // Set it to already called so it's not called twice when called by // performClickInternal() - mPrivateFlags |= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; + mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; } } } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index f39b73e671d4..5178a97e6b68 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -251,7 +251,7 @@ import java.util.Map; * density, or high density screens, respectively. For example: * <pre> * <link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio:1.5)" href="hdpi.css" /></pre> - * <p>The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ration of 1.5, + * <p>The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ratio of 1.5, * which is the high density pixel ratio. * </li> * </ul> diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java index 07593a512216..49e11b8baf51 100644 --- a/core/java/android/webkit/WebViewZygote.java +++ b/core/java/android/webkit/WebViewZygote.java @@ -19,6 +19,7 @@ package android.webkit; import android.app.LoadedApk; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.os.AsyncTask; import android.os.Build; import android.os.ChildZygoteProcess; import android.os.Process; @@ -93,11 +94,17 @@ public class WebViewZygote { synchronized (sLock) { sMultiprocessEnabled = enabled; - // When multi-process is disabled, kill the zygote. When it is enabled, - // the zygote is not explicitly started here to avoid waiting on the - // zygote launch at boot. Instead, the zygote will be started when it is - // first needed in getProcess(). - if (!enabled) { + // When toggling between multi-process being on/off, start or stop the + // zygote. If it is enabled and the zygote is not yet started, launch it. + // Otherwise, kill it. The name may be null if the package information has + // not yet been resolved. + if (enabled) { + // Run on a background thread as this waits for the zygote to start and we don't + // want to block the caller on this. It's okay if this is delayed as anyone trying + // to use the zygote will call it first anyway. + AsyncTask.THREAD_POOL_EXECUTOR.execute(WebViewZygote::getProcess); + } else { + // No need to run this in the background, it's very brief. stopZygoteLocked(); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 6fe64a03a95c..f77a6b72787f 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -291,6 +291,7 @@ import java.util.Locale; * @attr ref android.R.styleable#TextView_drawableTintMode * @attr ref android.R.styleable#TextView_lineSpacingExtra * @attr ref android.R.styleable#TextView_lineSpacingMultiplier + * @attr ref android.R.styleable#TextView_justificationMode * @attr ref android.R.styleable#TextView_marqueeRepeatLimit * @attr ref android.R.styleable#TextView_inputType * @attr ref android.R.styleable#TextView_imeOptions diff --git a/core/java/com/android/internal/backup/LocalTransportParameters.java b/core/java/com/android/internal/backup/LocalTransportParameters.java index 390fae96f810..154e79d4f7ef 100644 --- a/core/java/com/android/internal/backup/LocalTransportParameters.java +++ b/core/java/com/android/internal/backup/LocalTransportParameters.java @@ -16,62 +16,32 @@ package com.android.internal.backup; +import android.util.KeyValueSettingObserver; import android.content.ContentResolver; -import android.database.ContentObserver; import android.os.Handler; import android.provider.Settings; import android.util.KeyValueListParser; -import android.util.Slog; -class LocalTransportParameters { +class LocalTransportParameters extends KeyValueSettingObserver { private static final String TAG = "LocalTransportParams"; private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS; private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag"; - private final KeyValueListParser mParser = new KeyValueListParser(','); - private final ContentObserver mObserver; - private final ContentResolver mResolver; private boolean mFakeEncryptionFlag; LocalTransportParameters(Handler handler, ContentResolver resolver) { - mObserver = new Observer(handler); - mResolver = resolver; - } - - /** Observes for changes in the setting. This method MUST be paired with {@link #stop()}. */ - void start() { - mResolver.registerContentObserver(Settings.Secure.getUriFor(SETTING), false, mObserver); - update(); - } - - /** Stop observing for changes in the setting. */ - void stop() { - mResolver.unregisterContentObserver(mObserver); + super(handler, resolver, Settings.Secure.getUriFor(SETTING)); } boolean isFakeEncryptionFlag() { return mFakeEncryptionFlag; } - private void update() { - String parameters = ""; - try { - parameters = Settings.Secure.getString(mResolver, SETTING); - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Malformed " + SETTING + " setting: " + e.getMessage()); - } - mParser.setString(parameters); - mFakeEncryptionFlag = mParser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false); + public String getSettingValue(ContentResolver resolver) { + return Settings.Secure.getString(resolver, SETTING); } - private class Observer extends ContentObserver { - private Observer(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange) { - update(); - } + public void update(KeyValueListParser parser) { + mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false); } } diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java index 44adbb22eb7e..59504360f3cf 100644 --- a/core/java/com/android/internal/notification/SystemNotificationChannels.java +++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java @@ -50,6 +50,7 @@ public class SystemNotificationChannels { public static String FOREGROUND_SERVICE = "FOREGROUND_SERVICE"; public static String HEAVY_WEIGHT_APP = "HEAVY_WEIGHT_APP"; public static String SYSTEM_CHANGES = "SYSTEM_CHANGES"; + public static String DO_NOT_DISTURB = "DO_NOT_DISTURB"; public static void createAll(Context context) { final NotificationManager nm = context.getSystemService(NotificationManager.class); @@ -158,6 +159,11 @@ public class SystemNotificationChannels { NotificationManager.IMPORTANCE_LOW); channelsList.add(systemChanges); + NotificationChannel dndChanges = new NotificationChannel(DO_NOT_DISTURB, + context.getString(R.string.notification_channel_do_not_disturb), + NotificationManager.IMPORTANCE_LOW); + channelsList.add(dndChanges); + nm.createNotificationChannels(channelsList); } diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index 9d012de33089..0c5ea6327dff 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -23,6 +23,7 @@ import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.res.ColorStateList; +import android.content.res.Resources; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.util.Log; @@ -33,6 +34,7 @@ import android.view.LayoutInflater; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewDebug; import android.widget.LinearLayout; @@ -108,13 +110,6 @@ public final class MenuItemImpl implements MenuItem { private CharSequence mContentDescription; private CharSequence mTooltipText; - private static String sLanguage; - private static String sPrependShortcutLabel; - private static String sEnterShortcutLabel; - private static String sDeleteShortcutLabel; - private static String sSpaceShortcutLabel; - - /** * Instantiates this menu item. * @@ -130,20 +125,6 @@ public final class MenuItemImpl implements MenuItem { MenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering, CharSequence title, int showAsAction) { - String lang = menu.getContext().getResources().getConfiguration().locale.toString(); - if (sPrependShortcutLabel == null || !lang.equals(sLanguage)) { - sLanguage = lang; - // This is instantiated from the UI thread, so no chance of sync issues - sPrependShortcutLabel = menu.getContext().getResources().getString( - com.android.internal.R.string.prepend_shortcut_label); - sEnterShortcutLabel = menu.getContext().getResources().getString( - com.android.internal.R.string.menu_enter_shortcut_label); - sDeleteShortcutLabel = menu.getContext().getResources().getString( - com.android.internal.R.string.menu_delete_shortcut_label); - sSpaceShortcutLabel = menu.getContext().getResources().getString( - com.android.internal.R.string.menu_space_shortcut_label); - } - mMenu = menu; mId = id; mGroup = group; @@ -353,19 +334,45 @@ public final class MenuItemImpl implements MenuItem { return ""; } - StringBuilder sb = new StringBuilder(sPrependShortcutLabel); + final Resources res = mMenu.getContext().getResources(); + + StringBuilder sb = new StringBuilder(); + if (ViewConfiguration.get(mMenu.getContext()).hasPermanentMenuKey()) { + // Only prepend "Menu+" if there is a hardware menu key. + sb.append(res.getString( + com.android.internal.R.string.prepend_shortcut_label)); + } + + final int modifiers = + mMenu.isQwertyMode() ? mShortcutAlphabeticModifiers : mShortcutNumericModifiers; + appendModifier(sb, modifiers, KeyEvent.META_META_ON, res.getString( + com.android.internal.R.string.menu_meta_shortcut_label)); + appendModifier(sb, modifiers, KeyEvent.META_CTRL_ON, res.getString( + com.android.internal.R.string.menu_ctrl_shortcut_label)); + appendModifier(sb, modifiers, KeyEvent.META_ALT_ON, res.getString( + com.android.internal.R.string.menu_alt_shortcut_label)); + appendModifier(sb, modifiers, KeyEvent.META_SHIFT_ON, res.getString( + com.android.internal.R.string.menu_shift_shortcut_label)); + appendModifier(sb, modifiers, KeyEvent.META_SYM_ON, res.getString( + com.android.internal.R.string.menu_sym_shortcut_label)); + appendModifier(sb, modifiers, KeyEvent.META_FUNCTION_ON, res.getString( + com.android.internal.R.string.menu_function_shortcut_label)); + switch (shortcut) { case '\n': - sb.append(sEnterShortcutLabel); + sb.append(res.getString( + com.android.internal.R.string.menu_enter_shortcut_label)); break; case '\b': - sb.append(sDeleteShortcutLabel); + sb.append(res.getString( + com.android.internal.R.string.menu_delete_shortcut_label)); break; case ' ': - sb.append(sSpaceShortcutLabel); + sb.append(res.getString( + com.android.internal.R.string.menu_space_shortcut_label)); break; default: @@ -376,6 +383,12 @@ public final class MenuItemImpl implements MenuItem { return sb.toString(); } + private static void appendModifier(StringBuilder sb, int mask, int modifier, String label) { + if ((mask & modifier) == modifier) { + sb.append(label); + } + } + /** * @return Whether this menu item should be showing shortcuts (depends on * whether the menu should show shortcuts and whether this item has diff --git a/core/java/com/android/server/net/BaseNetdEventCallback.java b/core/java/com/android/server/net/BaseNetdEventCallback.java index 3d3a3d07b216..fdba2f3dc9e6 100644 --- a/core/java/com/android/server/net/BaseNetdEventCallback.java +++ b/core/java/com/android/server/net/BaseNetdEventCallback.java @@ -32,6 +32,12 @@ public class BaseNetdEventCallback extends INetdEventCallback.Stub { } @Override + public void onPrivateDnsValidationEvent(int netId, String ipAddress, + String hostname, boolean validated) { + // default no-op + } + + @Override public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) { // default no-op } diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 2c05d0b976fc..bd14d45325a7 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -309,7 +309,7 @@ namespace PaintGlue { jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) { minikin::Layout layout = MinikinUtils::doLayout( paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count, - nullptr, 0); + nullptr); size_t nGlyphs = layout.nGlyphs(); uint16_t* glyphs = new uint16_t[nGlyphs]; SkPoint* pos = new SkPoint[nGlyphs]; @@ -351,8 +351,7 @@ namespace PaintGlue { SkIRect ir; minikin::Layout layout = MinikinUtils::doLayout(&paint, - static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count, nullptr, - 0); + static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count, nullptr); minikin::MinikinRect rect; layout.getBounds(&rect); r.fLeft = rect.mLeft; @@ -468,7 +467,7 @@ namespace PaintGlue { } minikin::Layout layout = MinikinUtils::doLayout(paint, static_cast<minikin::Bidi>(bidiFlags), typeface, str.get(), 0, str.size(), - str.size(), nullptr, 0); + str.size(), nullptr); size_t nGlyphs = countNonSpaceGlyphs(layout); if (nGlyphs != 1 && nChars > 1) { // multiple-character input, and was not a ligature @@ -489,7 +488,7 @@ namespace PaintGlue { static const jchar ZZ_FLAG_STR[] = { 0xD83C, 0xDDFF, 0xD83C, 0xDDFF }; minikin::Layout zzLayout = MinikinUtils::doLayout(paint, static_cast<minikin::Bidi>(bidiFlags), typeface, ZZ_FLAG_STR, 0, 4, 4, - nullptr, 0); + nullptr); if (zzLayout.nGlyphs() != 1 || layoutContainsNotdef(zzLayout)) { // The font collection doesn't have a glyph for unknown flag. Just return true. return true; diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index 06de5daab7d2..0017f6cd8a41 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -484,7 +484,7 @@ static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray t const Typeface* typeface = paint->getAndroidTypeface(); jchar* jchars = env->GetCharArrayElements(text, NULL); get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y, - static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr, 0); + static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr); env->ReleaseCharArrayElements(text, jchars, JNI_ABORT); } @@ -496,13 +496,13 @@ static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring tex const int count = end - start; const jchar* jchars = env->GetStringChars(text, NULL); get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y, - static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr, 0); + static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr); env->ReleaseStringChars(text, jchars); } static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y, - jboolean isRtl, jlong paintHandle, jlong mtHandle, jint mtOffset) { + jboolean isRtl, jlong paintHandle, jlong mtHandle) { Paint* paint = reinterpret_cast<Paint*>(paintHandle); minikin::MeasuredText* mt = reinterpret_cast<minikin::MeasuredText*>(mtHandle); const Typeface* typeface = paint->getAndroidTypeface(); @@ -510,8 +510,7 @@ static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArra const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR; jchar* jchars = env->GetCharArrayElements(text, NULL); get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count, - contextCount, x, y, bidiFlags, *paint, typeface, mt, - mtOffset); + contextCount, x, y, bidiFlags, *paint, typeface, mt); env->ReleaseCharArrayElements(text, jchars, JNI_ABORT); } @@ -526,7 +525,7 @@ static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstr jint contextCount = contextEnd - contextStart; const jchar* jchars = env->GetStringChars(text, NULL); get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count, - contextCount, x, y, bidiFlags, *paint, typeface, nullptr, 0); + contextCount, x, y, bidiFlags, *paint, typeface, nullptr); env->ReleaseStringChars(text, jchars); } @@ -640,7 +639,7 @@ static const JNINativeMethod gDrawMethods[] = { {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray}, {"nDrawText","(J[CIIFFIJ)V", (void*) CanvasJNI::drawTextChars}, {"nDrawText","(JLjava/lang/String;IIFFIJ)V", (void*) CanvasJNI::drawTextString}, - {"nDrawTextRun","(J[CIIIIFFZJJI)V", (void*) CanvasJNI::drawTextRunChars}, + {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars}, {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString}, {"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars}, {"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString}, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index d05be2ca787b..7c8a52d1432b 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -71,6 +71,9 @@ using android::String8; using android::base::StringPrintf; using android::base::WriteStringToFile; +#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \ + append(StringPrintf(__VA_ARGS__)) + static pid_t gSystemServerPid = 0; static const char kZygoteClassName[] = "com/android/internal/os/Zygote"; @@ -186,30 +189,32 @@ static void UnsetChldSignalHandler() { // Calls POSIX setgroups() using the int[] object as an argument. // A NULL argument is tolerated. -static void SetGids(JNIEnv* env, jintArray javaGids) { +static bool SetGids(JNIEnv* env, jintArray javaGids, std::string* error_msg) { if (javaGids == NULL) { - return; + return true; } ScopedIntArrayRO gids(env, javaGids); if (gids.get() == NULL) { - RuntimeAbort(env, __LINE__, "Getting gids int array failed"); + *error_msg = CREATE_ERROR("Getting gids int array failed"); + return false; } int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0])); if (rc == -1) { - std::ostringstream oss; - oss << "setgroups failed: " << strerror(errno) << ", gids.size=" << gids.size(); - RuntimeAbort(env, __LINE__, oss.str().c_str()); + *error_msg = CREATE_ERROR("setgroups failed: %s, gids.size=%zu", strerror(errno), gids.size()); + return false; } + + return true; } // Sets the resource limits via setrlimit(2) for the values in the // two-dimensional array of integers that's passed in. The second dimension // contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is // treated as an empty array. -static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) { +static bool SetRLimits(JNIEnv* env, jobjectArray javaRlimits, std::string* error_msg) { if (javaRlimits == NULL) { - return; + return true; } rlimit rlim; @@ -219,7 +224,8 @@ static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) { ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i)); ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get())); if (javaRlimit.size() != 3) { - RuntimeAbort(env, __LINE__, "rlimits array must have a second dimension of size 3"); + *error_msg = CREATE_ERROR("rlimits array must have a second dimension of size 3"); + return false; } rlim.rlim_cur = javaRlimit[1]; @@ -227,11 +233,13 @@ static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) { int rc = setrlimit(javaRlimit[0], &rlim); if (rc == -1) { - ALOGE("setrlimit(%d, {%ld, %ld}) failed", javaRlimit[0], rlim.rlim_cur, + *error_msg = CREATE_ERROR("setrlimit(%d, {%ld, %ld}) failed", javaRlimit[0], rlim.rlim_cur, rlim.rlim_max); - RuntimeAbort(env, __LINE__, "setrlimit failed"); + return false; } } + + return true; } // The debug malloc library needs to know whether it's the zygote or a child. @@ -259,14 +267,16 @@ static void SetUpSeccompFilter(uid_t uid) { } } -static void EnableKeepCapabilities(JNIEnv* env) { +static bool EnableKeepCapabilities(std::string* error_msg) { int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); if (rc == -1) { - RuntimeAbort(env, __LINE__, "prctl(PR_SET_KEEPCAPS) failed"); + *error_msg = CREATE_ERROR("prctl(PR_SET_KEEPCAPS) failed: %s", strerror(errno)); + return false; } + return true; } -static void DropCapabilitiesBoundingSet(JNIEnv* env) { +static bool DropCapabilitiesBoundingSet(std::string* error_msg) { for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) { int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0); if (rc == -1) { @@ -274,14 +284,15 @@ static void DropCapabilitiesBoundingSet(JNIEnv* env) { ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify " "your kernel is compiled with file capabilities support"); } else { - ALOGE("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno)); - RuntimeAbort(env, __LINE__, "prctl(PR_CAPBSET_DROP) failed"); + *error_msg = CREATE_ERROR("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno)); + return false; } } } + return true; } -static void SetInheritable(JNIEnv* env, uint64_t inheritable) { +static bool SetInheritable(uint64_t inheritable, std::string* error_msg) { __user_cap_header_struct capheader; memset(&capheader, 0, sizeof(capheader)); capheader.version = _LINUX_CAPABILITY_VERSION_3; @@ -289,21 +300,23 @@ static void SetInheritable(JNIEnv* env, uint64_t inheritable) { __user_cap_data_struct capdata[2]; if (capget(&capheader, &capdata[0]) == -1) { - ALOGE("capget failed: %s", strerror(errno)); - RuntimeAbort(env, __LINE__, "capget failed"); + *error_msg = CREATE_ERROR("capget failed: %s", strerror(errno)); + return false; } capdata[0].inheritable = inheritable; capdata[1].inheritable = inheritable >> 32; if (capset(&capheader, &capdata[0]) == -1) { - ALOGE("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno)); - RuntimeAbort(env, __LINE__, "capset failed"); + *error_msg = CREATE_ERROR("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno)); + return false; } + + return true; } -static void SetCapabilities(JNIEnv* env, uint64_t permitted, uint64_t effective, - uint64_t inheritable) { +static bool SetCapabilities(uint64_t permitted, uint64_t effective, uint64_t inheritable, + std::string* error_msg) { __user_cap_header_struct capheader; memset(&capheader, 0, sizeof(capheader)); capheader.version = _LINUX_CAPABILITY_VERSION_3; @@ -319,18 +332,20 @@ static void SetCapabilities(JNIEnv* env, uint64_t permitted, uint64_t effective, capdata[1].inheritable = inheritable >> 32; if (capset(&capheader, &capdata[0]) == -1) { - ALOGE("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") failed: %s", permitted, - effective, inheritable, strerror(errno)); - RuntimeAbort(env, __LINE__, "capset failed"); + *error_msg = CREATE_ERROR("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") " + "failed: %s", permitted, effective, inheritable, strerror(errno)); + return false; } + return true; } -static void SetSchedulerPolicy(JNIEnv* env) { +static bool SetSchedulerPolicy(std::string* error_msg) { errno = -set_sched_policy(0, SP_DEFAULT); if (errno != 0) { - ALOGE("set_sched_policy(0, SP_DEFAULT) failed"); - RuntimeAbort(env, __LINE__, "set_sched_policy(0, SP_DEFAULT) failed"); + *error_msg = CREATE_ERROR("set_sched_policy(0, SP_DEFAULT) failed: %s", strerror(errno)); + return false; } + return true; } static int UnmountTree(const char* path) { @@ -364,7 +379,7 @@ static int UnmountTree(const char* path) { // Create a private mount namespace and bind mount appropriate emulated // storage for the given user. static bool MountEmulatedStorage(uid_t uid, jint mount_mode, - bool force_mount_namespace) { + bool force_mount_namespace, std::string* error_msg) { // See storage config details at http://source.android.com/tech/storage/ String8 storageSource; @@ -381,7 +396,7 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, // Create a second private mount namespace for our process if (unshare(CLONE_NEWNS) == -1) { - ALOGW("Failed to unshare(): %s", strerror(errno)); + *error_msg = CREATE_ERROR("Failed to unshare(): %s", strerror(errno)); return false; } @@ -392,7 +407,9 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage", NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) { - ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno)); + *error_msg = CREATE_ERROR("Failed to mount %s to /storage: %s", + storageSource.string(), + strerror(errno)); return false; } @@ -400,11 +417,14 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, userid_t user_id = multiuser_get_user_id(uid); const String8 userSource(String8::format("/mnt/user/%d", user_id)); if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) { + *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", userSource.string()); return false; } if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self", NULL, MS_BIND, NULL)) == -1) { - ALOGW("Failed to mount %s to /storage/self: %s", userSource.string(), strerror(errno)); + *error_msg = CREATE_ERROR("Failed to mount %s to /storage/self: %s", + userSource.string(), + strerror(errno)); return false; } @@ -436,31 +456,32 @@ static bool NeedsNoRandomizeWorkaround() { // descriptor (if any) is closed via dup2(), replacing it with a valid // (open) descriptor to /dev/null. -static void DetachDescriptors(JNIEnv* env, jintArray fdsToClose) { +static bool DetachDescriptors(JNIEnv* env, jintArray fdsToClose, std::string* error_msg) { if (!fdsToClose) { - return; + return true; } jsize count = env->GetArrayLength(fdsToClose); ScopedIntArrayRO ar(env, fdsToClose); if (ar.get() == NULL) { - RuntimeAbort(env, __LINE__, "Bad fd array"); + *error_msg = "Bad fd array"; + return false; } jsize i; int devnull; for (i = 0; i < count; i++) { devnull = open("/dev/null", O_RDWR); if (devnull < 0) { - ALOGE("Failed to open /dev/null: %s", strerror(errno)); - RuntimeAbort(env, __LINE__, "Failed to open /dev/null"); - continue; + *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno)); + return false; } ALOGV("Switching descriptor %d to /dev/null: %s", ar[i], strerror(errno)); if (dup2(devnull, ar[i]) < 0) { - ALOGE("Failed dup2() on descriptor %d: %s", ar[i], strerror(errno)); - RuntimeAbort(env, __LINE__, "Failed dup2()"); + *error_msg = StringPrintf("Failed dup2() on descriptor %d: %s", ar[i], strerror(errno)); + return false; } close(devnull); } + return true; } void SetThreadName(const char* thread_name) { @@ -495,20 +516,23 @@ void SetThreadName(const char* thread_name) { // The list of open zygote file descriptors. static FileDescriptorTable* gOpenFdTable = NULL; -static void FillFileDescriptorVector(JNIEnv* env, +static bool FillFileDescriptorVector(JNIEnv* env, jintArray java_fds, - std::vector<int>* fds) { + std::vector<int>* fds, + std::string* error_msg) { CHECK(fds != nullptr); if (java_fds != nullptr) { ScopedIntArrayRO ar(env, java_fds); if (ar.get() == nullptr) { - RuntimeAbort(env, __LINE__, "Bad fd array"); + *error_msg = "Bad fd array"; + return false; } fds->reserve(ar.size()); for (size_t i = 0; i < ar.size(); ++i) { fds->push_back(ar[i]); } } + return true; } // Utility routine to fork zygote and specialize the child process. @@ -526,32 +550,53 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra sigemptyset(&sigchld); sigaddset(&sigchld, SIGCHLD); + auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg) + __attribute__ ((noreturn)) { + const char* se_name_c_str = nullptr; + std::unique_ptr<ScopedUtfChars> se_name; + if (java_se_name != nullptr) { + se_name.reset(new ScopedUtfChars(env, java_se_name)); + se_name_c_str = se_name->c_str(); + } + if (se_name_c_str == nullptr && is_system_server) { + se_name_c_str = "system_server"; + } + const std::string& error_msg = (se_name_c_str == nullptr) + ? msg + : StringPrintf("(%s) %s", se_name_c_str, msg.c_str()); + env->FatalError(error_msg.c_str()); + __builtin_unreachable(); + }; + // Temporarily block SIGCHLD during forks. The SIGCHLD handler might // log, which would result in the logging FDs we close being reopened. // This would cause failures because the FDs are not whitelisted. // // Note that the zygote process is single threaded at this point. if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) { - ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)); - RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_BLOCK, { SIGCHLD }) failed."); + fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno))); } // Close any logging related FDs before we start evaluating the list of // file descriptors. __android_log_close(); + std::string error_msg; + // If this is the first fork for this zygote, create the open FD table. // If it isn't, we just need to check whether the list of open files has // changed (and it shouldn't in the normal case). std::vector<int> fds_to_ignore; - FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore); + if (!FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore, &error_msg)) { + fail_fn(error_msg); + } if (gOpenFdTable == NULL) { - gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore); + gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg); if (gOpenFdTable == NULL) { - RuntimeAbort(env, __LINE__, "Unable to construct file descriptor table."); + fail_fn(error_msg); } - } else if (!gOpenFdTable->Restat(fds_to_ignore)) { - RuntimeAbort(env, __LINE__, "Unable to restat file descriptor table."); + } else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) { + fail_fn(error_msg); } pid_t pid = fork(); @@ -560,17 +605,18 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra PreApplicationInit(); // Clean up any descriptors which must be closed immediately - DetachDescriptors(env, fdsToClose); + if (!DetachDescriptors(env, fdsToClose, &error_msg)) { + fail_fn(error_msg); + } // Re-open all remaining open file descriptors so that they aren't shared // with the zygote across a fork. - if (!gOpenFdTable->ReopenOrDetach()) { - RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors."); + if (!gOpenFdTable->ReopenOrDetach(&error_msg)) { + fail_fn(error_msg); } if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) { - ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)); - RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed."); + fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno))); } // Must be called when the new process still has CAP_SYS_ADMIN. The other alternative is to @@ -580,11 +626,17 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra // Keep capabilities across UID change, unless we're staying root. if (uid != 0) { - EnableKeepCapabilities(env); + if (!EnableKeepCapabilities(&error_msg)) { + fail_fn(error_msg); + } } - SetInheritable(env, permittedCapabilities); - DropCapabilitiesBoundingSet(env); + if (!SetInheritable(permittedCapabilities, &error_msg)) { + fail_fn(error_msg); + } + if (!DropCapabilitiesBoundingSet(&error_msg)) { + fail_fn(error_msg); + } bool use_native_bridge = !is_system_server && (instructionSet != NULL) && android::NativeBridgeAvailable(); @@ -601,8 +653,8 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra ALOGW("Native bridge will not be used because dataDir == NULL."); } - if (!MountEmulatedStorage(uid, mount_external, use_native_bridge)) { - ALOGW("Failed to mount emulated storage: %s", strerror(errno)); + if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg)) { + ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno)); if (errno == ENOTCONN || errno == EROFS) { // When device is actively encrypting, we get ENOTCONN here // since FUSE was mounted before the framework restarted. @@ -610,7 +662,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra // FUSE hasn't been created yet by init. // In either case, continue without external storage. } else { - RuntimeAbort(env, __LINE__, "Cannot continue without emulated storage"); + fail_fn(error_msg); } } @@ -625,9 +677,14 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra } } - SetGids(env, javaGids); + std::string error_msg; + if (!SetGids(env, javaGids, &error_msg)) { + fail_fn(error_msg); + } - SetRLimits(env, javaRlimits); + if (!SetRLimits(env, javaRlimits, &error_msg)) { + fail_fn(error_msg); + } if (use_native_bridge) { ScopedUtfChars isa_string(env, instructionSet); @@ -637,14 +694,12 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra int rc = setresgid(gid, gid, gid); if (rc == -1) { - ALOGE("setresgid(%d) failed: %s", gid, strerror(errno)); - RuntimeAbort(env, __LINE__, "setresgid failed"); + fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno))); } rc = setresuid(uid, uid, uid); if (rc == -1) { - ALOGE("setresuid(%d) failed: %s", uid, strerror(errno)); - RuntimeAbort(env, __LINE__, "setresuid failed"); + fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno))); } if (NeedsNoRandomizeWorkaround()) { @@ -656,9 +711,14 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra } } - SetCapabilities(env, permittedCapabilities, effectiveCapabilities, permittedCapabilities); + if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities, + &error_msg)) { + fail_fn(error_msg); + } - SetSchedulerPolicy(env); + if (!SetSchedulerPolicy(&error_msg)) { + fail_fn(error_msg); + } const char* se_info_c_str = NULL; ScopedUtfChars* se_info = NULL; @@ -666,7 +726,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra se_info = new ScopedUtfChars(env, java_se_info); se_info_c_str = se_info->c_str(); if (se_info_c_str == NULL) { - RuntimeAbort(env, __LINE__, "se_info_c_str == NULL"); + fail_fn("se_info_c_str == NULL"); } } const char* se_name_c_str = NULL; @@ -675,14 +735,13 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra se_name = new ScopedUtfChars(env, java_se_name); se_name_c_str = se_name->c_str(); if (se_name_c_str == NULL) { - RuntimeAbort(env, __LINE__, "se_name_c_str == NULL"); + fail_fn("se_name_c_str == NULL"); } } rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str); if (rc == -1) { - ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid, - is_system_server, se_info_c_str, se_name_c_str); - RuntimeAbort(env, __LINE__, "selinux_android_setcontext failed"); + fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid, + is_system_server, se_info_c_str, se_name_c_str)); } // Make it easier to debug audit logs by setting the main thread's name to the @@ -703,15 +762,14 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, is_system_server, is_child_zygote, instructionSet); if (env->ExceptionCheck()) { - RuntimeAbort(env, __LINE__, "Error calling post fork hooks."); + fail_fn("Error calling post fork hooks."); } } else if (pid > 0) { // the parent process // We blocked SIGCHLD prior to a fork, we unblock it here. if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) { - ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)); - RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed."); + fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno))); } } return pid; diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 2e6058268115..c5904e0e9e5e 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -123,14 +123,57 @@ FileDescriptorWhitelist::FileDescriptorWhitelist() FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr; +// Keeps track of all relevant information (flags, offset etc.) of an +// open zygote file descriptor. +class FileDescriptorInfo { + public: + // Create a FileDescriptorInfo for a given file descriptor. Returns + // |NULL| if an error occurred. + static FileDescriptorInfo* CreateFromFd(int fd, std::string* error_msg); + + // Checks whether the file descriptor associated with this object + // refers to the same description. + bool Restat() const; + + bool ReopenOrDetach(std::string* error_msg) const; + + const int fd; + const struct stat stat; + const std::string file_path; + const int open_flags; + const int fd_flags; + const int fs_flags; + const off_t offset; + const bool is_sock; + + private: + FileDescriptorInfo(int fd); + + FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags, + int fd_flags, int fs_flags, off_t offset); + + // Returns the locally-bound name of the socket |fd|. Returns true + // iff. all of the following hold : + // + // - the socket's sa_family is AF_UNIX. + // - the length of the path is greater than zero (i.e, not an unnamed socket). + // - the first byte of the path isn't zero (i.e, not a socket with an abstract + // address). + static bool GetSocketName(const int fd, std::string* result); + + bool DetachSocket(std::string* error_msg) const; + + DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo); +}; + // static -FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { +FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_msg) { struct stat f_stat; // This should never happen; the zygote should always have the right set // of permissions required to stat all its open files. if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) { - PLOG(ERROR) << "Unable to stat fd " << fd; - return NULL; + *error_msg = android::base::StringPrintf("Unable to stat %d", fd); + return nullptr; } const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get(); @@ -138,13 +181,15 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { if (S_ISSOCK(f_stat.st_mode)) { std::string socket_name; if (!GetSocketName(fd, &socket_name)) { - return NULL; + *error_msg = "Unable to get socket name"; + return nullptr; } if (!whitelist->IsAllowed(socket_name)) { - LOG(ERROR) << "Socket name not whitelisted : " << socket_name - << " (fd=" << fd << ")"; - return NULL; + *error_msg = android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)", + socket_name.c_str(), + fd); + return nullptr; } return new FileDescriptorInfo(fd); @@ -161,19 +206,22 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { // with the child process across forks but those should have been closed // before we got to this point. if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) { - LOG(ERROR) << "Unsupported st_mode " << f_stat.st_mode; - return NULL; + *error_msg = android::base::StringPrintf("Unsupported st_mode %u", f_stat.st_mode); + return nullptr; } std::string file_path; const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd); if (!android::base::Readlink(fd_path, &file_path)) { - return NULL; + *error_msg = android::base::StringPrintf("Could not read fd link %s: %s", + fd_path.c_str(), + strerror(errno)); + return nullptr; } if (!whitelist->IsAllowed(file_path)) { - LOG(ERROR) << "Not whitelisted : " << file_path; - return NULL; + *error_msg = std::string("Not whitelisted : ").append(file_path); + return nullptr; } // File descriptor flags : currently on FD_CLOEXEC. We can set these @@ -181,8 +229,11 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { // there won't be any races. const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)); if (fd_flags == -1) { - PLOG(ERROR) << "Failed fcntl(" << fd << ", F_GETFD)"; - return NULL; + *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s", + fd, + file_path.c_str(), + strerror(errno)); + return nullptr; } // File status flags : @@ -199,8 +250,11 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { // their presence and pass them in to open(). int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)); if (fs_flags == -1) { - PLOG(ERROR) << "Failed fcntl(" << fd << ", F_GETFL)"; - return NULL; + *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s", + fd, + file_path.c_str(), + strerror(errno)); + return nullptr; } // File offset : Ignore the offset for non seekable files. @@ -225,9 +279,9 @@ bool FileDescriptorInfo::Restat() const { return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev; } -bool FileDescriptorInfo::ReopenOrDetach() const { +bool FileDescriptorInfo::ReopenOrDetach(std::string* error_msg) const { if (is_sock) { - return DetachSocket(); + return DetachSocket(error_msg); } // NOTE: This might happen if the file was unlinked after being opened. @@ -236,31 +290,49 @@ bool FileDescriptorInfo::ReopenOrDetach() const { const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags)); if (new_fd == -1) { - PLOG(ERROR) << "Failed open(" << file_path << ", " << open_flags << ")"; + *error_msg = android::base::StringPrintf("Failed open(%s, %i): %s", + file_path.c_str(), + open_flags, + strerror(errno)); return false; } if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) { close(new_fd); - PLOG(ERROR) << "Failed fcntl(" << new_fd << ", F_SETFD, " << fd_flags << ")"; + *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s", + new_fd, + fd_flags, + file_path.c_str(), + strerror(errno)); return false; } if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) { close(new_fd); - PLOG(ERROR) << "Failed fcntl(" << new_fd << ", F_SETFL, " << fs_flags << ")"; + *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s", + new_fd, + fs_flags, + file_path.c_str(), + strerror(errno)); return false; } if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) { close(new_fd); - PLOG(ERROR) << "Failed lseek64(" << new_fd << ", SEEK_SET)"; + *error_msg = android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s", + new_fd, + file_path.c_str(), + strerror(errno)); return false; } if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) { close(new_fd); - PLOG(ERROR) << "Failed dup2(" << fd << ", " << new_fd << ")"; + *error_msg = android::base::StringPrintf("Failed dup2(%d, %d) (%s): %s", + fd, + new_fd, + file_path.c_str(), + strerror(errno)); return false; } @@ -336,20 +408,22 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) { return true; } -bool FileDescriptorInfo::DetachSocket() const { +bool FileDescriptorInfo::DetachSocket(std::string* error_msg) const { const int dev_null_fd = open("/dev/null", O_RDWR); if (dev_null_fd < 0) { - PLOG(ERROR) << "Failed to open /dev/null"; + *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno)); return false; } if (dup2(dev_null_fd, fd) == -1) { - PLOG(ERROR) << "Failed dup2 on socket descriptor " << fd; + *error_msg = android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s", + fd, + strerror(errno)); return false; } if (close(dev_null_fd) == -1) { - PLOG(ERROR) << "Failed close(" << dev_null_fd << ")"; + *error_msg = android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno)); return false; } @@ -357,11 +431,12 @@ bool FileDescriptorInfo::DetachSocket() const { } // static -FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore) { +FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore, + std::string* error_msg) { DIR* d = opendir(kFdPath); - if (d == NULL) { - PLOG(ERROR) << "Unable to open directory " << std::string(kFdPath); - return NULL; + if (d == nullptr) { + *error_msg = std::string("Unable to open directory ").append(kFdPath); + return nullptr; } int dir_fd = dirfd(d); dirent* e; @@ -377,7 +452,7 @@ FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ continue; } - FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd); + FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg); if (info == NULL) { if (closedir(d) == -1) { PLOG(ERROR) << "Unable to close directory"; @@ -388,19 +463,21 @@ FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ } if (closedir(d) == -1) { - PLOG(ERROR) << "Unable to close directory"; - return NULL; + *error_msg = "Unable to close directory"; + return nullptr; } return new FileDescriptorTable(open_fd_map); } -bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) { +bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg) { std::set<int> open_fds; // First get the list of open descriptors. DIR* d = opendir(kFdPath); if (d == NULL) { - PLOG(ERROR) << "Unable to open directory " << std::string(kFdPath); + *error_msg = android::base::StringPrintf("Unable to open directory %s: %s", + kFdPath, + strerror(errno)); return false; } @@ -420,21 +497,21 @@ bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) { } if (closedir(d) == -1) { - PLOG(ERROR) << "Unable to close directory"; + *error_msg = android::base::StringPrintf("Unable to close directory: %s", strerror(errno)); return false; } - return RestatInternal(open_fds); + return RestatInternal(open_fds, error_msg); } // Reopens all file descriptors that are contained in the table. Returns true // if all descriptors were successfully re-opened or detached, and false if an // error occurred. -bool FileDescriptorTable::ReopenOrDetach() { +bool FileDescriptorTable::ReopenOrDetach(std::string* error_msg) { std::unordered_map<int, FileDescriptorInfo*>::const_iterator it; for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) { const FileDescriptorInfo* info = it->second; - if (info == NULL || !info->ReopenOrDetach()) { + if (info == NULL || !info->ReopenOrDetach(error_msg)) { return false; } } @@ -447,7 +524,7 @@ FileDescriptorTable::FileDescriptorTable( : open_fd_map_(map) { } -bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) { +bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* error_msg) { bool error = false; // Iterate through the list of file descriptors we've already recorded @@ -455,6 +532,8 @@ bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) { // // (a) they continue to be open. // (b) they refer to the same file. + // + // We'll only store the last error message. std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin(); while (it != open_fd_map_.end()) { std::set<int>::const_iterator element = open_fds.find(it->first); @@ -475,7 +554,7 @@ bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) { // The file descriptor refers to a different description. We must // update our entry in the table. delete it->second; - it->second = FileDescriptorInfo::CreateFromFd(*element); + it->second = FileDescriptorInfo::CreateFromFd(*element, error_msg); if (it->second == NULL) { // The descriptor no longer no longer refers to a whitelisted file. // We flag an error and remove it from the list of files we're @@ -510,7 +589,7 @@ bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) { std::set<int>::const_iterator it; for (it = open_fds.begin(); it != open_fds.end(); ++it) { const int fd = (*it); - FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd); + FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg); if (info == NULL) { // A newly opened file is not on the whitelist. Flag an error and // continue. diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h index a39e387fde6c..a3570d7ed1fb 100644 --- a/core/jni/fd_utils.h +++ b/core/jni/fd_utils.h @@ -28,6 +28,8 @@ #include <android-base/macros.h> +class FileDescriptorInfo; + // Whitelist of open paths that the zygote is allowed to keep open. // // In addition to the paths listed in kPathWhitelist in file_utils.cpp, and @@ -66,49 +68,6 @@ class FileDescriptorWhitelist { DISALLOW_COPY_AND_ASSIGN(FileDescriptorWhitelist); }; -// Keeps track of all relevant information (flags, offset etc.) of an -// open zygote file descriptor. -class FileDescriptorInfo { - public: - // Create a FileDescriptorInfo for a given file descriptor. Returns - // |NULL| if an error occurred. - static FileDescriptorInfo* CreateFromFd(int fd); - - // Checks whether the file descriptor associated with this object - // refers to the same description. - bool Restat() const; - - bool ReopenOrDetach() const; - - const int fd; - const struct stat stat; - const std::string file_path; - const int open_flags; - const int fd_flags; - const int fs_flags; - const off_t offset; - const bool is_sock; - - private: - FileDescriptorInfo(int fd); - - FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags, - int fd_flags, int fs_flags, off_t offset); - - // Returns the locally-bound name of the socket |fd|. Returns true - // iff. all of the following hold : - // - // - the socket's sa_family is AF_UNIX. - // - the length of the path is greater than zero (i.e, not an unnamed socket). - // - the first byte of the path isn't zero (i.e, not a socket with an abstract - // address). - static bool GetSocketName(const int fd, std::string* result); - - bool DetachSocket() const; - - DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo); -}; - // A FileDescriptorTable is a collection of FileDescriptorInfo objects // keyed by their FDs. class FileDescriptorTable { @@ -116,19 +75,20 @@ class FileDescriptorTable { // Creates a new FileDescriptorTable. This function scans // /proc/self/fd for the list of open file descriptors and collects // information about them. Returns NULL if an error occurs. - static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore); + static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore, + std::string* error_msg); - bool Restat(const std::vector<int>& fds_to_ignore); + bool Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg); // Reopens all file descriptors that are contained in the table. Returns true // if all descriptors were successfully re-opened or detached, and false if an // error occurred. - bool ReopenOrDetach(); + bool ReopenOrDetach(std::string* error_msg); private: FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map); - bool RestatInternal(std::set<int>& open_fds); + bool RestatInternal(std::set<int>& open_fds, std::string* error_msg); static int ParseFd(dirent* e, int dir_fd); diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto index 914a7db56f1d..23c5661f0533 100644 --- a/core/proto/android/providers/settings.proto +++ b/core/proto/android/providers/settings.proto @@ -56,388 +56,455 @@ message GlobalSettingsProto { optional SettingProto enable_accessibility_global_gesture_enabled = 3 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto airplane_mode_on = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto theater_mode_on = 5 [ (android.privacy).dest = DEST_AUTOMATIC ]; - reserved 6,7,8,9,10; // Accidentally used. They are currently free to be reused. // A comma-separated list of radios that need to be disabled when airplane // mode is on. This overrides wifi_on and bluetooth_on if wifi and bluetooth // are included in the comma-separated list. - optional SettingProto airplane_mode_radios = 11 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto airplane_mode_toggleable_radios = 12 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_class_of_device = 293 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_disabled_profiles = 13; - optional SettingProto bluetooth_interoperability_list = 14; - optional SettingProto wifi_sleep_policy = 15 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto auto_time = 16 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto auto_time_zone = 17 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto car_dock_sound = 18; - optional SettingProto car_undock_sound = 19; - optional SettingProto desk_dock_sound = 20; - optional SettingProto desk_undock_sound = 21; - optional SettingProto dock_sounds_enabled = 22 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dock_sounds_enabled_when_accessibility = 23 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto lock_sound = 24; - optional SettingProto unlock_sound = 25; - optional SettingProto trusted_sound = 26; - optional SettingProto low_battery_sound = 27; - optional SettingProto power_sounds_enabled = 28 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wireless_charging_started_sound = 29; - optional SettingProto charging_sounds_enabled = 30 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto stay_on_while_plugged_in = 31 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bugreport_in_power_menu = 32 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto adb_enabled = 33 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto airplane_mode_radios = 6 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto airplane_mode_toggleable_radios = 7 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto bluetooth_class_of_device = 8 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto bluetooth_disabled_profiles = 9; + optional SettingProto bluetooth_interoperability_list = 10; + optional SettingProto wifi_sleep_policy = 11 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto auto_time = 12 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto auto_time_zone = 13 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto car_dock_sound = 14; + optional SettingProto car_undock_sound = 15; + optional SettingProto desk_dock_sound = 16; + optional SettingProto desk_undock_sound = 17; + optional SettingProto dock_sounds_enabled = 18 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dock_sounds_enabled_when_accessibility = 19 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lock_sound = 20; + optional SettingProto unlock_sound = 21; + optional SettingProto trusted_sound = 22; + optional SettingProto low_battery_sound = 23; + optional SettingProto power_sounds_enabled = 24 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wireless_charging_started_sound = 25; + optional SettingProto charging_sounds_enabled = 26 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto stay_on_while_plugged_in = 27 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto bugreport_in_power_menu = 28 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto adb_enabled = 29 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Whether views are allowed to save their attribute data. - optional SettingProto debug_view_attributes = 34 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto assisted_gps_enabled = 35 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_on = 36 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto cdma_cell_broadcast_sms = 37 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto cdma_roaming_mode = 38 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto cdma_subscription_mode = 39 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto data_activity_timeout_mobile = 40 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto data_activity_timeout_wifi = 41 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto data_roaming = 42 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto mdc_initial_max_retry = 43 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto force_allow_on_external = 44 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto euicc_provisioned = 294 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto development_force_resizable_activities = 45 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto development_enable_freeform_windows_support = 46 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto development_settings_enabled = 47 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto device_provisioned = 48 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto device_provisioning_mobile_data_enabled = 49 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto display_size_forced = 50 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto display_scaling_force = 51 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto download_max_bytes_over_mobile = 52 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto download_recommended_max_bytes_over_mobile = 53 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto hdmi_control_enabled = 54 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto hdmi_system_audio_control_enabled = 55 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto hdmi_control_auto_wakeup_enabled = 56 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto hdmi_control_auto_device_off_enabled = 57 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto location_background_throttle_interval_ms = 295 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto location_background_throttle_proximity_alert_interval_ms = 296 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto debug_view_attributes = 30 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto assisted_gps_enabled = 31 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto bluetooth_on = 32 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto cdma_cell_broadcast_sms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto cdma_roaming_mode = 34 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto cdma_subscription_mode = 35 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto data_activity_timeout_mobile = 36 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto data_activity_timeout_wifi = 37 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto data_roaming = 38 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mdc_initial_max_retry = 39 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto force_allow_on_external = 40 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto euicc_provisioned = 41 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto development_force_resizable_activities = 42 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto development_enable_freeform_windows_support = 43 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto development_settings_enabled = 44 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto device_provisioned = 45 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto device_provisioning_mobile_data_enabled = 46 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto display_size_forced = 47 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto display_scaling_force = 48 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto download_max_bytes_over_mobile = 49 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto download_recommended_max_bytes_over_mobile = 50 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto hdmi_control_enabled = 51 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto hdmi_system_audio_control_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto hdmi_control_auto_wakeup_enabled = 53 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto hdmi_control_auto_device_off_enabled = 54 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // If true, out-of-the-box execution for priv apps is enabled. + optional SettingProto priv_app_oob_enabled = 55 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto location_background_throttle_interval_ms = 56 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto location_background_throttle_proximity_alert_interval_ms = 57 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Packages that are whitelisted for background throttling (throttling will // not be applied). - optional SettingProto location_background_throttle_package_whitelist = 297 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_scan_background_throttle_interval_ms = 298 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_scan_background_throttle_package_whitelist = 299 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto mhl_input_switching_enabled = 58 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto mhl_power_charge_enabled = 59 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto mobile_data = 60 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto mobile_data_always_on = 61 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto connectivity_metrics_buffer_size = 62 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_enabled = 63 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_poll_interval = 64 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_time_cache_max_age = 65 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_global_alert_bytes = 66 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_sample_enabled = 67 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_augment_enabled = 300 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_dev_bucket_duration = 68 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_dev_persist_bytes = 69 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_dev_rotate_age = 70 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_dev_delete_age = 71 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_uid_bucket_duration = 72 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_uid_persist_bytes = 73 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_uid_rotate_age = 74 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_uid_delete_age = 75 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_uid_tag_bucket_duration = 76 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_uid_tag_persist_bytes = 77 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_uid_tag_rotate_age = 78 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto netstats_uid_tag_delete_age = 79 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto location_background_throttle_package_whitelist = 58 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_scan_background_throttle_interval_ms = 59 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_scan_background_throttle_package_whitelist = 60 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mhl_input_switching_enabled = 61 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mhl_power_charge_enabled = 62 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mobile_data = 63 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mobile_data_always_on = 64 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto connectivity_metrics_buffer_size = 65 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_enabled = 66 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_poll_interval = 67 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_time_cache_max_age = 68 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_global_alert_bytes = 69 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_sample_enabled = 70 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_augment_enabled = 71 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_dev_bucket_duration = 72 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_dev_persist_bytes = 73 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_dev_rotate_age = 74 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_dev_delete_age = 75 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_uid_bucket_duration = 76 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_uid_persist_bytes = 77 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_uid_rotate_age = 78 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_uid_delete_age = 79 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_uid_tag_bucket_duration = 80 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_uid_tag_persist_bytes = 81 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_uid_tag_rotate_age = 82 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto netstats_uid_tag_delete_age = 83 [ (android.privacy).dest = DEST_AUTOMATIC ]; // User preference for which network(s) should be used. - optional SettingProto network_preference = 80; - optional SettingProto network_scorer_app = 81 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto nitz_update_diff = 82 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto nitz_update_spacing = 83 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto ntp_server = 84; - optional SettingProto ntp_timeout = 85 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto storage_benchmark_interval = 86 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dns_resolver_sample_validity_seconds = 87 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dns_resolver_success_threshold_percent = 88 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dns_resolver_min_samples = 89 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dns_resolver_max_samples = 90 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_preference = 84; + optional SettingProto network_scorer_app = 85 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto night_display_forced_auto_mode_available = 86 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto nitz_update_diff = 87 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto nitz_update_spacing = 88 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ntp_server = 89; + optional SettingProto ntp_timeout = 90 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto storage_benchmark_interval = 91 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dns_resolver_sample_validity_seconds = 92 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dns_resolver_success_threshold_percent = 93 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dns_resolver_min_samples = 94 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dns_resolver_max_samples = 95 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Whether to disable the automatic scheduling of system updates. - optional SettingProto ota_disable_automatic_update = 91 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto package_verifier_enable = 92 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto package_verifier_timeout = 93 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto package_verifier_default_response = 94; - optional SettingProto package_verifier_setting_visible = 95 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto package_verifier_include_adb = 96 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto fstrim_mandatory_interval = 97 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto pdp_watchdog_poll_interval_ms = 98 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto pdp_watchdog_long_poll_interval_ms = 99 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto pdp_watchdog_error_poll_interval_ms = 100 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto pdp_watchdog_trigger_packet_count = 101 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto pdp_watchdog_error_poll_count = 102 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto pdp_watchdog_max_pdp_reset_fail_count = 103 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto setup_prepaid_data_service_url = 105; - optional SettingProto setup_prepaid_detection_target_url = 106; - optional SettingProto setup_prepaid_detection_redir_host = 107; - optional SettingProto sms_outgoing_check_interval_ms = 108 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sms_outgoing_check_max_count = 109 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ota_disable_automatic_update = 96 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto package_verifier_enable = 97 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto package_verifier_timeout = 98 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto package_verifier_default_response = 99; + optional SettingProto package_verifier_setting_visible = 100 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto package_verifier_include_adb = 101 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto fstrim_mandatory_interval = 102 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto pdp_watchdog_poll_interval_ms = 103 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto pdp_watchdog_long_poll_interval_ms = 104 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto pdp_watchdog_error_poll_interval_ms = 105 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto pdp_watchdog_trigger_packet_count = 106 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto pdp_watchdog_error_poll_count = 107 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto pdp_watchdog_max_pdp_reset_fail_count = 108 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto setup_prepaid_data_service_url = 109; + optional SettingProto setup_prepaid_detection_target_url = 110; + optional SettingProto setup_prepaid_detection_redir_host = 111; + optional SettingProto sms_outgoing_check_interval_ms = 112 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sms_outgoing_check_max_count = 113 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Used to disable SMS short code confirmation. Defaults to true. - optional SettingProto sms_short_code_confirmation = 110 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sms_short_code_rule = 111 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tcp_default_init_rwnd = 112 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tether_supported = 113 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tether_dun_required = 114 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tether_dun_apn = 115; - optional SettingProto tether_offload_disabled = 301 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sms_short_code_confirmation = 114 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sms_short_code_rule = 115 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tcp_default_init_rwnd = 116 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tether_supported = 117 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tether_dun_required = 118 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tether_dun_apn = 119; + optional SettingProto tether_offload_disabled = 120 [ (android.privacy).dest = DEST_AUTOMATIC ]; // List of carrier app certificate mapped to carrier app package id which are whitelisted to // prompt the user for install when a SIM card with matching UICC carrier privilege rules is // inserted. - optional SettingProto carrier_app_whitelist = 116 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto carrier_app_names = 358 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto usb_mass_storage_enabled = 117 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto use_google_mail = 118 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto webview_data_reduction_proxy_key = 119; - optional SettingProto webview_fallback_logic_enabled = 120 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto carrier_app_whitelist = 121 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto carrier_app_names = 122 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto usb_mass_storage_enabled = 123 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto use_google_mail = 124 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto webview_data_reduction_proxy_key = 125; + optional SettingProto webview_fallback_logic_enabled = 126 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Name of the package used as WebView provider. - optional SettingProto webview_provider = 121 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto webview_multiprocess = 122 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto network_switch_notification_daily_limit = 123 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto network_switch_notification_rate_limit_millis = 124 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto network_avoid_bad_wifi = 125 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto network_metered_multipath_preference = 302 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto network_watchlist_last_report_time = 303 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_badging_thresholds = 304 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_display_on = 126 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_display_certification_on = 127 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_display_wps_config = 128 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_networks_available_notification_on = 129 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wimax_networks_available_notification_on = 130 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_networks_available_repeat_delay = 131 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_country_code = 132; - optional SettingProto wifi_framework_scan_interval_ms = 133 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_idle_ms = 134 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_num_open_networks_kept = 135 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_on = 136 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_scan_always_available = 137 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_wakeup_enabled = 138 [ (android.privacy).dest = DEST_AUTOMATIC ]; - reserved 305; // Removed wifi_wakeup_available - optional SettingProto network_scoring_ui_enabled = 306 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto speed_label_cache_eviction_age_millis = 307 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto recommended_network_evaluator_cache_expiry_ms = 308 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto network_recommendations_enabled = 139 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto network_recommendations_package = 286 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto use_open_wifi_package = 309 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto network_recommendation_request_timeout_ms = 310 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto ble_scan_always_available = 140 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_saved_state = 141 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_supplicant_scan_interval_ms = 142 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_enhanced_auto_join = 143 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_network_show_rssi = 144 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_scan_interval_when_p2p_connected_ms = 145 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_watchdog_on = 146 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_watchdog_poor_network_test_enabled = 147 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_suspend_optimizations_enabled = 148 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_verbose_logging_enabled = 149 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_connected_mac_randomization_enabled = 350 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_max_dhcp_retry_count = 150 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_mobile_data_transition_wakelock_timeout_ms = 151 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_device_owner_configs_lockdown = 152 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_frequency_band = 153 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_p2p_device_name = 154; - optional SettingProto wifi_reenable_delay_ms = 155 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_ephemeral_out_of_range_timeout_ms = 156 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto data_stall_alarm_non_aggressive_delay_in_ms = 157 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto data_stall_alarm_aggressive_delay_in_ms = 158 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto provisioning_apn_alarm_delay_in_ms = 159 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto gprs_register_check_period_ms = 160 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wtf_is_fatal = 161 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto webview_provider = 127 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto webview_multiprocess = 128 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_switch_notification_daily_limit = 129 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_switch_notification_rate_limit_millis = 130 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_avoid_bad_wifi = 131 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_metered_multipath_preference = 132 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_watchlist_last_report_time = 133 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_badging_thresholds = 134 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_display_on = 135 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_display_certification_on = 136 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_display_wps_config = 137 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_networks_available_notification_on = 138 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_carrier_networks_available_notification_on = 139 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wimax_networks_available_notification_on = 140 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_networks_available_repeat_delay = 141 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_country_code = 142; + optional SettingProto wifi_framework_scan_interval_ms = 143 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_idle_ms = 144 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_num_open_networks_kept = 145 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_on = 146 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_scan_always_available = 147 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto soft_ap_timeout_enabled = 148 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_wakeup_enabled = 149 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_scoring_ui_enabled = 150 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto speed_label_cache_eviction_age_millis = 151 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto recommended_network_evaluator_cache_expiry_ms = 152 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_recommendations_enabled = 153 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_recommendations_package = 154 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto use_open_wifi_package = 155 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_recommendation_request_timeout_ms = 156 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ble_scan_always_available = 157 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ble_scan_low_power_window_ms = 158 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ble_scan_balanced_window_ms = 159 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ble_scan_low_latency_window_ms = 160 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ble_scan_low_power_interval_ms = 161 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ble_scan_balanced_interval_ms = 162 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ble_scan_low_latency_interval_ms = 163 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_saved_state = 164 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_supplicant_scan_interval_ms = 165 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_enhanced_auto_join = 166 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_network_show_rssi = 167 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_scan_interval_when_p2p_connected_ms = 168 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_watchdog_on = 169 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_watchdog_poor_network_test_enabled = 170 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_suspend_optimizations_enabled = 171 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_verbose_logging_enabled = 172 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_connected_mac_randomization_enabled = 173 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_max_dhcp_retry_count = 174 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_mobile_data_transition_wakelock_timeout_ms = 175 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_device_owner_configs_lockdown = 176 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_frequency_band = 177 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_p2p_device_name = 178; + optional SettingProto wifi_reenable_delay_ms = 179 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_ephemeral_out_of_range_timeout_ms = 180 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto data_stall_alarm_non_aggressive_delay_in_ms = 181 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto data_stall_alarm_aggressive_delay_in_ms = 182 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto provisioning_apn_alarm_delay_in_ms = 183 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto gprs_register_check_period_ms = 184 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wtf_is_fatal = 185 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Ringer mode. A change in this value will not reflect as a change in the // ringer mode. - optional SettingProto mode_ringer = 162 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mode_ringer = 186 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Overlay display devices setting. // The value is a specially formatted string that describes the size and // density of simulated secondary devices. // Format: {width}x{height}/dpi;... - optional SettingProto overlay_display_devices = 163 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto battery_discharge_duration_threshold = 164 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto battery_discharge_threshold = 165 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto send_action_app_error = 166 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dropbox_age_seconds = 167 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dropbox_max_files = 168 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dropbox_quota_kb = 169 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dropbox_quota_percent = 170 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dropbox_reserve_percent = 171 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dropbox_tag_prefix = 172 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto error_logcat_prefix = 173 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sys_free_storage_log_interval = 174 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto disk_free_change_reporting_threshold = 175 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sys_storage_threshold_percentage = 176 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sys_storage_threshold_max_bytes = 177 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sys_storage_full_threshold_bytes = 178 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sys_storage_cache_percentage = 311 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sys_storage_cache_max_bytes = 312 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sync_max_retry_delay_in_seconds = 179 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto connectivity_change_delay = 180 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto connectivity_sampling_interval_in_seconds = 181 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto pac_change_delay = 182 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto captive_portal_mode = 183 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto captive_portal_detection_enabled = 313 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto captive_portal_server = 184; - optional SettingProto captive_portal_https_url = 185; - optional SettingProto captive_portal_http_url = 186; - optional SettingProto captive_portal_fallback_url = 187; - optional SettingProto captive_portal_other_fallback_urls = 314; - optional SettingProto captive_portal_use_https = 188 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto captive_portal_user_agent = 189; - optional SettingProto nsd_on = 190 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto overlay_display_devices = 187 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto battery_discharge_duration_threshold = 188 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto battery_discharge_threshold = 189 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto send_action_app_error = 190 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dropbox_age_seconds = 191 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dropbox_max_files = 192 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dropbox_quota_kb = 193 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dropbox_quota_percent = 194 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dropbox_reserve_percent = 195 [ (android.privacy).dest = DEST_AUTOMATIC ]; + repeated SettingProto dropbox_settings = 196; + repeated SettingProto error_logcat_lines = 197; + optional SettingProto sys_free_storage_log_interval = 198 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto disk_free_change_reporting_threshold = 199 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sys_storage_threshold_percentage = 200 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sys_storage_threshold_max_bytes = 201 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sys_storage_full_threshold_bytes = 202 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sys_storage_cache_percentage = 203 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sys_storage_cache_max_bytes = 204 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sync_max_retry_delay_in_seconds = 205 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto connectivity_change_delay = 206 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto connectivity_sampling_interval_in_seconds = 207 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto pac_change_delay = 208 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto captive_portal_mode = 209 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto captive_portal_detection_enabled = 210 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto captive_portal_server = 211; + optional SettingProto captive_portal_https_url = 212; + optional SettingProto captive_portal_http_url = 213; + optional SettingProto captive_portal_fallback_url = 214; + optional SettingProto captive_portal_other_fallback_urls = 215; + optional SettingProto captive_portal_use_https = 216 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto captive_portal_user_agent = 217; + optional SettingProto nsd_on = 218 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Let user pick default install location. - optional SettingProto set_install_location = 191 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto default_install_location = 192 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto inet_condition_debounce_up_delay = 193 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto inet_condition_debounce_down_delay = 194 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto read_external_storage_enforced_default = 195 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto http_proxy = 196; - optional SettingProto global_http_proxy_host = 197; - optional SettingProto global_http_proxy_port = 198; - optional SettingProto global_http_proxy_exclusion_list = 199; - optional SettingProto global_http_proxy_pac = 200; + optional SettingProto set_install_location = 219 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto default_install_location = 220 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto inet_condition_debounce_up_delay = 221 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto inet_condition_debounce_down_delay = 222 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto read_external_storage_enforced_default = 223 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto http_proxy = 224; + optional SettingProto global_http_proxy_host = 225; + optional SettingProto global_http_proxy_port = 226; + optional SettingProto global_http_proxy_exclusion_list = 227; + optional SettingProto global_http_proxy_pac = 228; // Enables the UI setting to allow the user to specify the global HTTP proxy // and associated exclusion list. - optional SettingProto set_global_http_proxy = 201 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto default_dns_server = 202; + optional SettingProto set_global_http_proxy = 229 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto default_dns_server = 230; // The requested Private DNS mode and an accompanying specifier. - optional SettingProto private_dns_mode = 315; - optional SettingProto private_dns_specifier = 316; - optional SettingProto bluetooth_headset_priority_prefix = 203 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_a2dp_sink_priority_prefix = 204 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_a2dp_src_priority_prefix = 205 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_a2dp_supports_optional_codecs_prefix = 287 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_a2dp_optional_codecs_enabled_prefix = 288 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_input_device_priority_prefix = 206 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_map_priority_prefix = 207 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_map_client_priority_prefix = 208 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_pbap_client_priority_prefix = 209 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_sap_priority_prefix = 210 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_pan_priority_prefix = 211 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_hearing_aid_priority_prefix = 345 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto activity_manager_constants = 317; - optional SettingProto device_idle_constants = 212; - optional SettingProto device_idle_constants_watch = 213; - optional SettingProto battery_saver_constants = 318; - optional SettingProto anomaly_detection_constants = 319; - optional SettingProto always_on_display_constants = 320; - optional SettingProto app_idle_constants = 214; - optional SettingProto power_manager_constants = 321; - optional SettingProto alarm_manager_constants = 215; - optional SettingProto job_scheduler_constants = 216; - optional SettingProto shortcut_manager_constants = 217; - optional SettingProto device_policy_constants = 322; - optional SettingProto text_classifier_constants = 323; - optional SettingProto window_animation_scale = 218 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto transition_animation_scale = 219 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto animator_duration_scale = 220 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto fancy_ime_animations = 221 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto compatibility_mode = 222 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto emergency_tone = 223 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto call_auto_retry = 224 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto emergency_affordance_needed = 225 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto preferred_network_mode = 226 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto private_dns_mode = 231; + optional SettingProto private_dns_specifier = 232; + repeated SettingProto bluetooth_headset_priorities = 233; + repeated SettingProto bluetooth_a2dp_sink_priorities = 234; + repeated SettingProto bluetooth_a2dp_src_priorities = 235; + repeated SettingProto bluetooth_a2dp_supports_optional_codecs = 236; + repeated SettingProto bluetooth_a2dp_optional_codecs_enabled = 237; + repeated SettingProto bluetooth_input_device_priorities = 238; + repeated SettingProto bluetooth_map_priorities = 239; + repeated SettingProto bluetooth_map_client_priorities = 240; + repeated SettingProto bluetooth_pbap_client_priorities = 241; + repeated SettingProto bluetooth_sap_priorities = 242; + repeated SettingProto bluetooth_pan_priorities = 243; + repeated SettingProto bluetooth_hearing_aid_priorities = 244; + // These are key=value lists, separated by commas. + optional SettingProto activity_manager_constants = 245; + optional SettingProto device_idle_constants = 246; + optional SettingProto battery_saver_constants = 247; + optional SettingProto battery_saver_device_specific_constants = 248; + optional SettingProto battery_tip_constants = 249; + optional SettingProto anomaly_detection_constants = 250; + // Version of the anomaly config. + optional SettingProto anomaly_config_version = 251 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // A base64-encoded string represents anomaly stats config. + optional SettingProto anomaly_config = 252; + // This is a key=value list, separated by commas. + optional SettingProto always_on_display_constants = 253; + // System VDSO global setting. This links to the "sys.vdso" system property. + // The following values are supported: + // false -> both 32 and 64 bit vdso disabled + // 32 -> 32 bit vdso enabled + // 64 -> 64 bit vdso enabled + // Any other value defaults to both 32 bit and 64 bit true. + optional SettingProto sys_vdso = 254 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // UidCpuPower global setting. This links the sys.uidcpupower system property. + // The following values are supported: + // 0 -> /proc/uid_cpupower/* are disabled + // 1 -> /proc/uid_cpupower/* are enabled + // Any other value defaults to enabled. + optional SettingProto sys_uidcpupower = 255 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // An integer to reduce the FPS by this factor. Only for experiments. + optional SettingProto fps_divisor = 256 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // Flag to enable or disable display panel low power mode (lpm) + // false -> Display panel power saving mode is disabled. + // true -> Display panel power saving mode is enabled. + optional SettingProto display_panel_lpm = 257 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // These are key=value lists, separated by commas. + optional SettingProto app_idle_constants = 258; + optional SettingProto power_manager_constants = 259; + optional SettingProto alarm_manager_constants = 260; + optional SettingProto job_scheduler_constants = 261; + optional SettingProto shortcut_manager_constants = 262; + optional SettingProto device_policy_constants = 263; + optional SettingProto text_classifier_constants = 264; + optional SettingProto battery_stats_constants = 265; + optional SettingProto sync_manager_constants = 266; + optional SettingProto app_standby_enabled = 267 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto app_auto_restriction_enabled = 268 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto forced_app_standby_enabled = 269 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto forced_app_standby_for_small_battery_enabled = 270 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto off_body_radios_off_for_small_battery_enabled = 271 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto off_body_radios_off_delay_ms = 272 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_on_when_proxy_disconnected = 273 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto time_only_mode_enabled = 274 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_watchlist_enabled = 275 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto keep_profile_in_background = 276 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto window_animation_scale = 277 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto transition_animation_scale = 278 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto animator_duration_scale = 279 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto fancy_ime_animations = 280 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto compatibility_mode = 281 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto emergency_tone = 282 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto call_auto_retry = 283 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto emergency_affordance_needed = 284 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto preferred_network_mode = 285 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Name of an application package to be debugged. - optional SettingProto debug_app = 227; - optional SettingProto wait_for_debugger = 228 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enable_gpu_debug_layers = 342 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto debug_app = 286; + optional SettingProto wait_for_debugger = 287 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enable_gpu_debug_layers = 288 [ (android.privacy).dest = DEST_AUTOMATIC ]; // App allowed to load GPU debug layers. - optional SettingProto gpu_debug_app = 343; - optional SettingProto gpu_debug_layers = 344 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto low_power_mode = 229 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto low_power_mode_trigger_level = 230 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto always_finish_activities = 231 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dock_audio_media_enabled = 232 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto encoded_surround_output = 233 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto audio_safe_volume_state = 234 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tzinfo_update_content_url = 235; - optional SettingProto tzinfo_update_metadata_url = 236; - optional SettingProto selinux_update_content_url = 237; - optional SettingProto selinux_update_metadata_url = 238; - optional SettingProto sms_short_codes_update_content_url = 239; - optional SettingProto sms_short_codes_update_metadata_url = 240; - optional SettingProto apn_db_update_content_url = 241; - optional SettingProto apn_db_update_metadata_url = 242; - optional SettingProto cert_pin_update_content_url = 243; - optional SettingProto cert_pin_update_metadata_url = 244; - optional SettingProto intent_firewall_update_content_url = 245; - optional SettingProto intent_firewall_update_metadata_url = 246; - optional SettingProto lang_id_update_content_url = 324; - optional SettingProto lang_id_update_metadata_url = 325; - optional SettingProto smart_selection_update_content_url = 326; - optional SettingProto smart_selection_update_metadata_url = 327; - optional SettingProto selinux_status = 247 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto development_force_rtl = 248 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto low_battery_sound_timeout = 249 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wifi_bounce_delay_override_ms = 250 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto policy_control = 251 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto zen_mode = 252 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto zen_mode_ringer_level = 253 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto zen_mode_config_etag = 254; - optional SettingProto heads_up_notifications_enabled = 255 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto device_name = 256; - optional SettingProto network_scoring_provisioned = 257 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto require_password_to_decrypt = 258 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enhanced_4g_mode_enabled = 259 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto vt_ims_enabled = 260 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wfc_ims_enabled = 261 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wfc_ims_mode = 262 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wfc_ims_roaming_mode = 263 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wfc_ims_roaming_enabled = 264 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto lte_service_forced = 265 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto ephemeral_cookie_max_size_bytes = 266 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enable_ephemeral_feature = 267 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto instant_app_dexopt_enabled = 328 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto installed_instant_app_min_cache_period = 268 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto installed_instant_app_max_cache_period = 289 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto uninstalled_instant_app_min_cache_period = 290 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto uninstalled_instant_app_max_cache_period = 291 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto unused_static_shared_lib_min_cache_period = 292 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto allow_user_switching_when_system_user_locked = 269 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto boot_count = 270 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto safe_boot_disallowed = 271 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto device_demo_mode = 272 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto network_access_timeout_ms = 329 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto database_downgrade_reason = 274; - optional SettingProto database_creation_buildid = 330 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto contacts_database_wal_enabled = 275 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto location_settings_link_to_permissions_enabled = 331 [ (android.privacy).dest = DEST_AUTOMATIC ]; - reserved 332; // Removed backup_refactored_service_disabled - optional SettingProto euicc_factory_reset_timeout_millis = 333 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto storage_settings_clobber_threshold = 334 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto chained_battery_attribution_enabled = 353 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto hidden_api_blacklist_exemptions = 355 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto gpu_debug_app = 289; + optional SettingProto gpu_debug_layers = 290 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto low_power_mode = 291 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // Battery level [1-100] at which low power mode automatically turns on. If + // 0, it will not automatically turn on. + optional SettingProto low_power_mode_trigger_level = 292 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // The max value for {@link #LOW_POWER_MODE_TRIGGER_LEVEL}. If this setting + // is not set or the value is 0, the default max will be used. + optional SettingProto low_power_mode_trigger_level_max = 293 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto always_finish_activities = 294 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dock_audio_media_enabled = 295 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto encoded_surround_output = 296 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto audio_safe_volume_state = 297 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tzinfo_update_content_url = 298; + optional SettingProto tzinfo_update_metadata_url = 299; + optional SettingProto selinux_update_content_url = 300; + optional SettingProto selinux_update_metadata_url = 301; + optional SettingProto sms_short_codes_update_content_url = 302; + optional SettingProto sms_short_codes_update_metadata_url = 303; + optional SettingProto apn_db_update_content_url = 304; + optional SettingProto apn_db_update_metadata_url = 305; + optional SettingProto cert_pin_update_content_url = 306; + optional SettingProto cert_pin_update_metadata_url = 307; + optional SettingProto intent_firewall_update_content_url = 308; + optional SettingProto intent_firewall_update_metadata_url = 309; + optional SettingProto lang_id_update_content_url = 310; + optional SettingProto lang_id_update_metadata_url = 311; + optional SettingProto smart_selection_update_content_url = 312; + optional SettingProto smart_selection_update_metadata_url = 313; + optional SettingProto selinux_status = 314 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto development_force_rtl = 315 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto low_battery_sound_timeout = 316 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wifi_bounce_delay_override_ms = 317 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto policy_control = 318 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto emulate_display_cutout = 319 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto zen_mode = 320 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto zen_mode_ringer_level = 321 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto zen_mode_config_etag = 322; + // If 0, turning on dnd manually will last indefinitely. Else if + // non-negative, turning on dnd manually will last for this many minutes. + // Else (if negative), turning on dnd manually will surface a dialog that + // prompts user to specify a duration. + optional SettingProto zen_duration = 323 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto heads_up_notifications_enabled = 324 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto device_name = 325; + optional SettingProto network_scoring_provisioned = 326 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto require_password_to_decrypt = 327 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enhanced_4g_mode_enabled = 328 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto vt_ims_enabled = 329 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wfc_ims_enabled = 330 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wfc_ims_mode = 331 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wfc_ims_roaming_mode = 332 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wfc_ims_roaming_enabled = 333 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lte_service_forced = 334 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ephemeral_cookie_max_size_bytes = 335 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enable_ephemeral_feature = 336 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto instant_app_dexopt_enabled = 337 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto installed_instant_app_min_cache_period = 338 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto installed_instant_app_max_cache_period = 339 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto uninstalled_instant_app_min_cache_period = 340 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto uninstalled_instant_app_max_cache_period = 341 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto unused_static_shared_lib_min_cache_period = 342 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto allow_user_switching_when_system_user_locked = 343 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto boot_count = 344 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto safe_boot_disallowed = 345 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto device_demo_mode = 346 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto network_access_timeout_ms = 347 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto database_downgrade_reason = 348; + optional SettingProto database_creation_buildid = 349 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto contacts_database_wal_enabled = 350 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto location_settings_link_to_permissions_enabled = 351 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto euicc_factory_reset_timeout_millis = 352 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto storage_settings_clobber_threshold = 353 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link + // Secure#LOCATION_MODE_OFF} temporarily for all users. + optional SettingProto location_global_kill_switch = 354 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will + // be ignored and restoring to lower version of platform API will be + // skipped. + optional SettingProto override_settings_provider_restore_any_version = 355 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto chained_battery_attribution_enabled = 356 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto autofill_compat_allowed_packages = 357 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto hidden_api_blacklist_exemptions = 358 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Subscription to be used for voice call on a multi sim device. The // supported values are 0 = SUB1, 1 = SUB2 and etc. - optional SettingProto multi_sim_voice_call_subscription = 276 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto multi_sim_voice_prompt = 277 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto multi_sim_data_call_subscription = 278 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto multi_sim_sms_subscription = 279 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto multi_sim_sms_prompt = 280 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto multi_sim_voice_call_subscription = 359 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto multi_sim_voice_prompt = 360 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto multi_sim_data_call_subscription = 361 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto multi_sim_sms_subscription = 362 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto multi_sim_sms_prompt = 363 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Whether to enable new contacts aggregator or not. // 1 = enable, 0 = disable. - optional SettingProto new_contact_aggregator = 281 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto contact_metadata_sync_enabled = 282 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enable_cellular_on_boot = 283 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto max_notification_enqueue_rate = 284 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto show_notification_channel_warnings = 335 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto cell_on = 285 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto show_temperature_warning = 336 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto warning_temperature = 337 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enable_diskstats_logging = 338 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enable_cache_quota_calculation = 339 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enable_deletion_helper_no_threshold_toggle = 340 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto notification_snooze_options = 341 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enable_gnss_raw_meas_full_tracking = 346 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto install_carrier_app_notification_persistent = 356 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto install_carrier_app_notification_sleep_millis = 357 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto zram_enabled = 347 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto smart_replies_in_notifications_flags = 348 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto show_first_crash_dialog = 349 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto show_restart_in_crash_dialog = 351 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto show_mute_in_crash_dialog = 352 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingsProto show_zen_upgrade_notification = 354 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingsProto app_auto_restriction_enabled = 359 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingsProto zen_duration = 360 [ (android.privacy).dest = DEST_AUTOMATIC ]; - + optional SettingProto new_contact_aggregator = 364 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto contact_metadata_sync_enabled = 365 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enable_cellular_on_boot = 366 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto max_notification_enqueue_rate = 367 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_notification_channel_warnings = 368 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto cell_on = 369 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_temperature_warning = 370 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto warning_temperature = 371 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enable_diskstats_logging = 372 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enable_cache_quota_calculation = 373 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enable_deletion_helper_no_threshold_toggle = 374 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto notification_snooze_options = 375 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // Configuration flags for SQLite Compatibility WAL. Encoded as a key-value + // list, separated by commas. + // E.g.: compatibility_wal_supported=true, wal_syncmode=OFF + optional SettingProto sqlite_compatibility_wal_flags = 376 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enable_gnss_raw_meas_full_tracking = 377 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto install_carrier_app_notification_persistent = 378 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto install_carrier_app_notification_sleep_millis = 379 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto zram_enabled = 380 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto smart_replies_in_notifications_flags = 381 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_first_crash_dialog = 382 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_restart_in_crash_dialog = 383 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_mute_in_crash_dialog = 384 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingsProto show_zen_upgrade_notification = 385 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Please insert fields in the same order as in // frameworks/base/core/java/android/provider/Settings.java. - // Next tag = 361; + // Next tag = 386; } message SecureSettingsProto { @@ -454,227 +521,229 @@ message SecureSettingsProto { optional SettingProto voice_interaction_service = 7 [ (android.privacy).dest = DEST_AUTOMATIC ]; // The currently selected autofill service flattened ComponentName. optional SettingProto autofill_service = 8 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_hci_log = 9; - optional SettingProto user_setup_complete = 10 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // Boolean indicating if Autofill supports field classification. + optional SettingProto autofill_feature_field_classification = 9 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto autofill_user_data_max_user_data_size = 10 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto autofill_user_data_max_field_classification_ids_size = 11 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto autofill_user_data_max_category_count = 12 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto autofill_user_data_max_value_length = 13 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto autofill_user_data_min_value_length = 14 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto user_setup_complete = 15 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Whether the current user has been set up via setup wizard (0 = false, // 1 = true). This value differs from USER_SETUP_COMPLETE in that it can be // reset back to 0 in case SetupWizard has been re-enabled on TV devices. - optional SettingProto tv_user_setup_complete = 170 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto completed_category_prefix = 11 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enabled_input_methods = 12 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto disabled_system_input_methods = 13 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto show_ime_with_hard_keyboard = 14 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto always_on_vpn_app = 15; - optional SettingProto always_on_vpn_lockdown = 16 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto install_non_market_apps = 17 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto unknown_sources_default_reversed = 171 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tv_user_setup_complete = 16 [ (android.privacy).dest = DEST_AUTOMATIC ]; + repeated SettingProto completed_categories = 17; + optional SettingProto enabled_input_methods = 18 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto disabled_system_input_methods = 19 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_ime_with_hard_keyboard = 20 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto always_on_vpn_app = 21; + optional SettingProto always_on_vpn_lockdown = 22 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto install_non_market_apps = 23 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto unknown_sources_default_reversed = 24 [ (android.privacy).dest = DEST_AUTOMATIC ]; // The degree of location access enabled by the user. - optional SettingProto location_mode = 18 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto location_previous_mode = 19; + optional SettingProto location_mode = 25 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // The App or module that changes the location mode. + optional SettingProto location_changer = 26 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Whether lock-to-app will lock the keyguard when exiting. - optional SettingProto lock_to_app_exit_locked = 20 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto lock_screen_lock_after_timeout = 21 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto lock_screen_allow_private_notifications = 172 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto lock_screen_allow_remote_input = 22 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto show_note_about_notification_hiding = 23 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto trust_agents_initialized = 24 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto parental_control_enabled = 25 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto parental_control_last_update = 26 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto parental_control_redirect_url = 27 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto settings_classname = 28 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_enabled = 29 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_shortcut_enabled = 173 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_shortcut_on_lock_screen = 174 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_shortcut_dialog_shown = 175 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_shortcut_target_service = 176 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lock_to_app_exit_locked = 27 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lock_screen_lock_after_timeout = 28 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lock_screen_allow_private_notifications = 29 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lock_screen_allow_remote_input = 30 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_note_about_notification_hiding = 31 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto trust_agents_initialized = 32 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto parental_control_enabled = 33 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto parental_control_last_update = 34 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto parental_control_redirect_url = 35 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto settings_classname = 36 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_enabled = 37 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_shortcut_enabled = 38 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_shortcut_on_lock_screen = 39 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_shortcut_dialog_shown = 40 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_shortcut_target_service = 41 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Setting specifying the accessibility service or feature to be toggled via // the accessibility button in the navigation bar. This is either a // flattened ComponentName or the class name of a system class implementing // a supported accessibility feature. - optional SettingProto accessibility_button_target_component = 177 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto touch_exploration_enabled = 30 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_button_target_component = 42 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto touch_exploration_enabled = 43 [ (android.privacy).dest = DEST_AUTOMATIC ]; // List of the enabled accessibility providers. - optional SettingProto enabled_accessibility_services = 31; + optional SettingProto enabled_accessibility_services = 44; // List of the accessibility services to which the user has granted // permission to put the device into touch exploration mode. - optional SettingProto touch_exploration_granted_accessibility_services = 32; + optional SettingProto touch_exploration_granted_accessibility_services = 45; + // Uri of the slice that's presented on the keyguard. Defaults to a slice + // with the date and next alarm. + optional SettingProto keyguard_slice_uri = 46; // Whether to speak passwords while in accessibility mode. - optional SettingProto accessibility_speak_password = 33 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_high_text_contrast_enabled = 34 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_script_injection = 35; - optional SettingProto accessibility_screen_reader_url = 36; - optional SettingProto accessibility_web_content_key_bindings = 37; - optional SettingProto accessibility_display_magnification_enabled = 38 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_display_magnification_navbar_enabled = 178 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_display_magnification_scale = 39 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_display_magnification_auto_update = 179 [deprecated = true]; - optional SettingProto accessibility_soft_keyboard_mode = 40 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_captioning_enabled = 41 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_captioning_locale = 42 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_captioning_preset = 43 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_captioning_background_color = 44 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_captioning_foreground_color = 45 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_captioning_edge_type = 46 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_captioning_edge_color = 47 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_captioning_window_color = 48 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_captioning_typeface = 49 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_captioning_font_scale = 50 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_display_inversion_enabled = 51 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_display_daltonizer_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_display_daltonizer = 53 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_autoclick_enabled = 54 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_autoclick_delay = 55 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accessibility_large_pointer_icon = 56 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto long_press_timeout = 57 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto multi_press_timeout = 58 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enabled_print_services = 59; - optional SettingProto disabled_print_services = 60; - optional SettingProto display_density_forced = 61 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tts_default_rate = 62 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tts_default_pitch = 63 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tts_default_synth = 64 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tts_default_locale = 65 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tts_enabled_plugins = 66; - optional SettingProto connectivity_release_pending_intent_delay_ms = 67 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto allowed_geolocation_origins = 68; - optional SettingProto preferred_tty_mode = 69 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enhanced_voice_privacy_enabled = 70 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tty_mode_enabled = 71 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto backup_enabled = 72 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto backup_auto_restore = 73 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto backup_provisioned = 74 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto backup_transport = 75 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto last_setup_shown = 76 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_global_search_activity = 77 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_num_promoted_sources = 78 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_max_results_to_display = 79 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_max_results_per_source = 80 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_web_results_override_limit = 81 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_promoted_source_deadline_millis = 82 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_source_timeout_millis = 83 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_prefill_millis = 84 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_max_stat_age_millis = 85 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_max_source_event_age_millis = 86 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_min_impressions_for_source_ranking = 87 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_min_clicks_for_source_ranking = 88 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_max_shortcuts_returned = 89 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_query_thread_core_pool_size = 90 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_query_thread_max_pool_size = 91 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_shortcut_refresh_core_pool_size = 92 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_shortcut_refresh_max_pool_size = 93 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_thread_keepalive_seconds = 94 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto search_per_source_concurrent_query_limit = 95 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_speak_password = 47 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_high_text_contrast_enabled = 48 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_display_magnification_enabled = 49 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_display_magnification_navbar_enabled = 50 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_display_magnification_scale = 51 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_soft_keyboard_mode = 52 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_captioning_enabled = 53 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_captioning_locale = 54 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_captioning_preset = 55 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_captioning_background_color = 56 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_captioning_foreground_color = 57 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_captioning_edge_type = 58 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_captioning_edge_color = 59 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_captioning_window_color = 60 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_captioning_typeface = 61 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_captioning_font_scale = 62 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_display_inversion_enabled = 63 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_display_daltonizer_enabled = 64 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // Integer property that specifies the type of color space adjustment to perform. + optional SettingProto accessibility_display_daltonizer = 65 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_autoclick_enabled = 66 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_autoclick_delay = 67 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_large_pointer_icon = 68 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto long_press_timeout = 69 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto multi_press_timeout = 70 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enabled_print_services = 71; + optional SettingProto disabled_print_services = 72; + optional SettingProto display_density_forced = 73 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tts_default_rate = 74 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tts_default_pitch = 75 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tts_default_synth = 76 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tts_default_locale = 77 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tts_enabled_plugins = 78; + optional SettingProto connectivity_release_pending_intent_delay_ms = 79 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto allowed_geolocation_origins = 80; + optional SettingProto preferred_tty_mode = 81 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enhanced_voice_privacy_enabled = 82 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tty_mode_enabled = 83 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto backup_enabled = 84 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto backup_auto_restore = 85 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto backup_provisioned = 86 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto backup_transport = 87 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto last_setup_shown = 88 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_global_search_activity = 89 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_num_promoted_sources = 90 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_max_results_to_display = 91 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_max_results_per_source = 92 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_web_results_override_limit = 93 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_promoted_source_deadline_millis = 94 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_source_timeout_millis = 95 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_prefill_millis = 96 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_max_stat_age_millis = 97 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_max_source_event_age_millis = 98 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_min_impressions_for_source_ranking = 99 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_min_clicks_for_source_ranking = 100 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_max_shortcuts_returned = 101 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_query_thread_core_pool_size = 102 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_query_thread_max_pool_size = 103 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_shortcut_refresh_core_pool_size = 104 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_shortcut_refresh_max_pool_size = 105 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_thread_keepalive_seconds = 106 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto search_per_source_concurrent_query_limit = 107 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Whether or not alert sounds are played on StorageManagerService events. - optional SettingProto mount_play_notification_snd = 96 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto mount_ums_autostart = 97 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto mount_ums_prompt = 98 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto mount_ums_notify_enabled = 99 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto anr_show_background = 100 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mount_play_notification_snd = 108 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mount_ums_autostart = 109 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mount_ums_prompt = 110 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mount_ums_notify_enabled = 111 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto anr_show_background = 112 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_first_crash_dialog_dev_option = 113 [ (android.privacy).dest = DEST_AUTOMATIC ]; // The ComponentName string of the service to be used as the voice // recognition service. - optional SettingProto voice_recognition_service = 101 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto package_verifier_user_consent = 102 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto selected_spell_checker = 103 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto selected_spell_checker_subtype = 104 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto spell_checker_enabled = 105 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto incall_power_button_behavior = 106 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto incall_back_button_behavior = 107 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto wake_gesture_enabled = 108 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto doze_enabled = 109 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto doze_always_on = 110 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto doze_pulse_on_pick_up = 111 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto doze_pulse_on_long_press = 180 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto doze_pulse_on_double_tap = 112 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto ui_night_mode = 113 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto screensaver_enabled = 114 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto screensaver_components = 115 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto screensaver_activate_on_dock = 116 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto screensaver_activate_on_sleep = 117 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto screensaver_default_component = 118 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto nfc_payment_default_component = 119 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto nfc_payment_foreground = 120 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sms_default_application = 121 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dialer_default_application = 122 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto emergency_assistance_application = 123 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto assist_structure_enabled = 124 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto assist_screenshot_enabled = 125 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto assist_disclosure_enabled = 126 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto voice_recognition_service = 114 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto package_verifier_user_consent = 115 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto selected_spell_checker = 116 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto selected_spell_checker_subtype = 117 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto spell_checker_enabled = 118 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto incall_power_button_behavior = 119 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto incall_back_button_behavior = 120 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto wake_gesture_enabled = 121 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto doze_enabled = 122 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto doze_always_on = 123 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto doze_pulse_on_pick_up = 124 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto doze_pulse_on_long_press = 125 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto doze_pulse_on_double_tap = 126 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ui_night_mode = 127 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screensaver_enabled = 128 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screensaver_components = 129 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screensaver_activate_on_dock = 130 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screensaver_activate_on_sleep = 131 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screensaver_default_component = 132 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto nfc_payment_default_component = 133 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto nfc_payment_foreground = 134 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sms_default_application = 135 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dialer_default_application = 136 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto emergency_assistance_application = 137 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto assist_structure_enabled = 138 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto assist_screenshot_enabled = 139 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto assist_disclosure_enabled = 140 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_rotation_suggestions = 141 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto num_rotation_suggestions_accepted = 142 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Read only list of the service components that the current user has // explicitly allowed to see and assist with all of the user's // notifications. - optional SettingProto enabled_notification_assistant = 127 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enabled_notification_listeners = 128 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto enabled_notification_policy_access_packages = 129 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enabled_notification_assistant = 143 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enabled_notification_listeners = 144 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enabled_notification_policy_access_packages = 145 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Defines whether managed profile ringtones should be synced from its // parent profile. - optional SettingProto sync_parent_sounds = 130 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto immersive_mode_confirmations = 131 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sync_parent_sounds = 146 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto immersive_mode_confirmations = 147 [ (android.privacy).dest = DEST_AUTOMATIC ]; // The query URI to find a print service to install. - optional SettingProto print_service_search_uri = 132 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto print_service_search_uri = 148 [ (android.privacy).dest = DEST_AUTOMATIC ]; // The query URI to find an NFC service to install. - optional SettingProto payment_service_search_uri = 133 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto payment_service_search_uri = 149 [ (android.privacy).dest = DEST_AUTOMATIC ]; // The query URI to find an auto fill service to install. - optional SettingProto autofill_service_search_uri = 181 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto skip_first_use_hints = 134 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto unsafe_volume_music_active_ms = 135 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto lock_screen_show_notifications = 136 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tv_input_hidden_inputs = 137; - optional SettingProto tv_input_custom_labels = 138; - optional SettingProto usb_audio_automatic_routing_disabled = 139 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sleep_timeout = 140 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto double_tap_to_wake = 141 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto autofill_service_search_uri = 150 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto skip_first_use_hints = 151 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto unsafe_volume_music_active_ms = 152 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lock_screen_show_notifications = 153 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tv_input_hidden_inputs = 154; + optional SettingProto tv_input_custom_labels = 155; + optional SettingProto usb_audio_automatic_routing_disabled = 156 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sleep_timeout = 157 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto double_tap_to_wake = 158 [ (android.privacy).dest = DEST_AUTOMATIC ]; // The current assistant component. It could be a voice interaction service, // or an activity that handles ACTION_ASSIST, or empty, which means using // the default handling. - optional SettingProto assistant = 142 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto camera_gesture_disabled = 143 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto camera_double_tap_power_gesture_disabled = 144 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto camera_double_twist_to_flip_enabled = 145 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto camera_lift_trigger_enabled = 182 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto assist_gesture_enabled = 183 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto assist_gesture_sensitivity = 184 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto assist_gesture_silence_alerts_enabled = 185 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto assist_gesture_wake_enabled = 186 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto assist_gesture_setup_complete = 187 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto night_display_activated = 146 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto night_display_auto_mode = 147 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto night_display_color_temperature = 188 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto night_display_custom_start_time = 148 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto night_display_custom_end_time = 149 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto night_display_last_activated_time = 189 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto brightness_use_twilight = 150; - optional SettingProto enabled_vr_listeners = 151 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto vr_display_mode = 152 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto carrier_apps_handled = 153 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto managed_profile_contact_remote_search = 154 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto automatic_storage_manager_enabled = 155 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto automatic_storage_manager_days_to_retain = 156 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto automatic_storage_manager_bytes_cleared = 157 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto automatic_storage_manager_last_run = 158 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto automatic_storage_manager_turned_off_by_policy = 190 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto system_navigation_keys_enabled = 159 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto downloads_backup_enabled = 160; - optional SettingProto downloads_backup_allow_metered = 161; - optional SettingProto downloads_backup_charging_only = 162; - optional SettingProto automatic_storage_manager_downloads_days_to_retain = 163; + optional SettingProto assistant = 159 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto camera_gesture_disabled = 160 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto camera_double_tap_power_gesture_disabled = 161 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto camera_double_twist_to_flip_enabled = 162 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto camera_lift_trigger_enabled = 163 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto assist_gesture_enabled = 164 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto assist_gesture_sensitivity = 165 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto assist_gesture_silence_alerts_enabled = 166 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto assist_gesture_wake_enabled = 167 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto assist_gesture_setup_complete = 168 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto night_display_activated = 169 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto night_display_auto_mode = 170 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto night_display_color_temperature = 171 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto night_display_custom_start_time = 172 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto night_display_custom_end_time = 173 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto night_display_last_activated_time = 174 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto enabled_vr_listeners = 175 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto vr_display_mode = 176 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto carrier_apps_handled = 177 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto managed_profile_contact_remote_search = 178 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto automatic_storage_manager_enabled = 179 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto automatic_storage_manager_days_to_retain = 180 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto automatic_storage_manager_bytes_cleared = 181 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto automatic_storage_manager_last_run = 182 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto automatic_storage_manager_turned_off_by_policy = 183 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto system_navigation_keys_enabled = 184 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Holds comma-separated list of ordering of QuickSettings tiles. - optional SettingProto qs_tiles = 164 [ (android.privacy).dest = DEST_AUTOMATIC ]; - reserved 165; // Removed demo_user_setup_complete - optional SettingProto instant_apps_enabled = 166 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto device_paired = 167 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto package_verifier_state = 191 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto cmas_additional_broadcast_pkg = 192 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto notification_badging = 168 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto qs_auto_added_tiles = 193 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto lockdown_in_power_menu = 194 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto backup_manager_constants = 169; - optional SettingProto show_first_crash_dialog_dev_option = 195 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto bluetooth_on_while_driving = 196 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto backup_local_transport_parameters = 197; - + optional SettingProto qs_tiles = 185 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto instant_apps_enabled = 186 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto device_paired = 187 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto package_verifier_state = 188 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto cmas_additional_broadcast_pkg = 189 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto notification_badging = 190 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto qs_auto_added_tiles = 191 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lockdown_in_power_menu = 192 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto backup_manager_constants = 193; + optional SettingProto backup_local_transport_parameters = 194; + optional SettingProto bluetooth_on_while_driving = 195 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Please insert fields in the same order as in // frameworks/base/core/java/android/provider/Settings.java. - // Next tag = 198 + // Next tag = 196 } message SystemSettingsProto { @@ -688,29 +757,31 @@ message SystemSettingsProto { optional SettingProto bluetooth_discoverability_timeout = 5 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto font_scale = 6 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto system_locales = 7 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto display_color_mode = 67 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto screen_off_timeout = 8 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto screen_brightness = 9 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto screen_brightness_for_vr = 10 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto screen_brightness_mode = 11 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto screen_auto_brightness_adj = 12 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto display_color_mode = 8 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screen_off_timeout = 9 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screen_brightness = 10 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screen_brightness_for_vr = 11 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screen_brightness_mode = 12 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screen_auto_brightness_adj = 13 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Determines which streams are affected by ringer mode changes. The stream // type's bit will be set to 1 if it should be muted when going into an // inaudible ringer mode. - optional SettingProto mode_ringer_streams_affected = 13 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto mute_streams_affected = 14 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto vibrate_on = 15 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto vibrate_input_devices = 16 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto volume_ring = 17 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto volume_system = 18 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto volume_voice = 19 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto volume_music = 20 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto volume_alarm = 21 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto volume_notification = 22 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto volume_bluetooth_sco = 23 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto volume_accessibility = 68 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto volume_master = 24 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto master_mono = 25 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mode_ringer_streams_affected = 14 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto mute_streams_affected = 15 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto vibrate_on = 16 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto vibrate_input_devices = 17 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto notification_vibration_intensity = 18 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto haptic_feedback_intensity = 19 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto volume_ring = 20 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto volume_system = 21 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto volume_voice = 22 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto volume_music = 23 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto volume_alarm = 24 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto volume_notification = 25 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto volume_bluetooth_sco = 26 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto volume_accessibility = 27 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto volume_master = 28 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto master_mono = 29 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Whether silent mode should allow vibration feedback. This is used // internally in AudioService and the Sound settings activity to coordinate // decoupling of vibrate and silent modes. This setting will likely be @@ -719,59 +790,63 @@ message SystemSettingsProto { // Not used anymore. On devices with vibrator, the user explicitly selects // silent or vibrate mode. Kept for use by legacy database upgrade code in // DatabaseHelper. - optional SettingProto vibrate_in_silent = 26 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto vibrate_in_silent = 30 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Appended to various volume related settings to record the previous values // before the settings were affected by a silent/vibrate ringer mode change. - optional SettingProto append_for_last_audible = 27 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto ringtone = 28; - optional SettingProto ringtone_cache = 29; - optional SettingProto notification_sound = 30; - optional SettingProto notification_sound_cache = 31; - optional SettingProto alarm_alert = 32; - optional SettingProto alarm_alert_cache = 33; - optional SettingProto media_button_receiver = 34; - optional SettingProto text_auto_replace = 35 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto text_auto_caps = 36 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto text_auto_punctuate = 37 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto text_show_password = 38 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto show_gtalk_service_status = 39 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto time_12_24 = 40 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto date_format = 41 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto setup_wizard_has_run = 42 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto accelerometer_rotation = 43 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto user_rotation = 44 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto hide_rotation_lock_toggle_for_accessibility = 45 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto vibrate_when_ringing = 46 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dtmf_tone_when_dialing = 47 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto dtmf_tone_type_when_dialing = 48 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto hearing_aid = 49 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto tty_mode = 50 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sound_effects_enabled = 51 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto haptic_feedback_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto notification_light_pulse = 53 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto append_for_last_audible = 31 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ringtone = 32; + optional SettingProto ringtone_cache = 33; + optional SettingProto notification_sound = 34; + optional SettingProto notification_sound_cache = 35; + optional SettingProto alarm_alert = 36; + optional SettingProto alarm_alert_cache = 37; + optional SettingProto media_button_receiver = 38; + optional SettingProto text_auto_replace = 39 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto text_auto_caps = 40 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto text_auto_punctuate = 41 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto text_show_password = 42 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_gtalk_service_status = 43 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto time_12_24 = 44 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto date_format = 45 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto setup_wizard_has_run = 46 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accelerometer_rotation = 47 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto user_rotation = 48 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto hide_rotation_lock_toggle_for_accessibility = 49 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto vibrate_when_ringing = 50 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dtmf_tone_when_dialing = 51 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto dtmf_tone_type_when_dialing = 52 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto hearing_aid = 53 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto tty_mode = 54 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // User-selected RTT mode. When on, outgoing and incoming calls will be + // answered as RTT calls when supported by the device and carrier. Boolean + // value. + optional SettingProto rtt_calling_mode = 55 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sound_effects_enabled = 56 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto haptic_feedback_enabled = 57 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto notification_light_pulse = 58 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Show pointer location on screen? 0 = no, 1 = yes. - optional SettingProto pointer_location = 54 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto show_touches = 55 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto pointer_location = 59 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_touches = 60 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Log raw orientation data from {@link // com.android.server.policy.WindowOrientationListener} for use with the // orientationplot.py tool. // 0 = no, 1 = yes - optional SettingProto window_orientation_listener_log = 56 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto lockscreen_sounds_enabled = 57 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto lockscreen_disabled = 58 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sip_receive_calls = 59 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sip_call_options = 60 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sip_always = 61 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto sip_address_only = 62 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto pointer_speed = 63 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto lock_to_app_enabled = 64 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto egg_mode = 65 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto show_battery_percent = 69 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto when_to_make_wifi_calls = 66 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto window_orientation_listener_log = 61 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lockscreen_sounds_enabled = 62 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lockscreen_disabled = 63 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sip_receive_calls = 64 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sip_call_options = 65 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sip_always = 66 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto sip_address_only = 67 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto pointer_speed = 68 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto lock_to_app_enabled = 69 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto egg_mode = 70 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_battery_percent = 71 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto when_to_make_wifi_calls = 72 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Please insert fields in the same order as in // frameworks/base/core/java/android/provider/Settings.java. - // Next tag = 70; + // Next tag = 73; } message SettingProto { diff --git a/core/proto/android/server/animationadapter.proto b/core/proto/android/server/animationadapter.proto new file mode 100644 index 000000000000..c4ffe8c477aa --- /dev/null +++ b/core/proto/android/server/animationadapter.proto @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; + +import "frameworks/base/core/proto/android/graphics/point.proto"; +import "frameworks/base/core/proto/android/view/remote_animation_target.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; + +package com.android.server.wm.proto; +option java_multiple_files = true; + +message AnimationAdapterProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional LocalAnimationAdapterProto local = 1; + optional RemoteAnimationAdapterWrapperProto remote = 2; +} + +/* represents RemoteAnimationAdapterWrapper */ +message RemoteAnimationAdapterWrapperProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional .android.view.RemoteAnimationTargetProto target = 1; +} + +/* represents LocalAnimationAdapter */ +message LocalAnimationAdapterProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional AnimationSpecProto animation_spec = 1; +} + +message AnimationSpecProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional WindowAnimationSpecProto window = 1; + optional MoveAnimationSpecProto move = 2; + optional AlphaAnimationSpecProto alpha = 3; +} + +/* represents WindowAnimationSpec */ +message WindowAnimationSpecProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional string animation = 1; +} + +/* represents MoveAnimationSpec*/ +message MoveAnimationSpecProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional .android.graphics.PointProto from = 1; + optional .android.graphics.PointProto to = 2; + optional int64 duration = 3; +} + +/* represents AlphaAnimationSpec */ +message AlphaAnimationSpecProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional float from = 1; + optional float to = 2; + optional int64 duration = 3; +}
\ No newline at end of file diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto index 64aa98b1136e..c58de563692b 100644 --- a/core/proto/android/server/powermanagerservice.proto +++ b/core/proto/android/server/powermanagerservice.proto @@ -198,7 +198,7 @@ message WakeLockProto { } optional .android.os.WakeLockLevelEnum lock_level = 1; - optional string tag = 2 [ (.android.privacy).dest = DEST_EXPLICIT ]; + optional string tag = 2; optional WakeLockFlagsProto flags = 3; optional bool is_disabled = 4; // Acquire time in ms diff --git a/core/proto/android/server/surfaceanimator.proto b/core/proto/android/server/surfaceanimator.proto index 7f7839e6f7f1..dcc2b3443f2b 100644 --- a/core/proto/android/server/surfaceanimator.proto +++ b/core/proto/android/server/surfaceanimator.proto @@ -16,6 +16,7 @@ syntax = "proto2"; +import "frameworks/base/core/proto/android/server/animationadapter.proto"; import "frameworks/base/core/proto/android/view/surfacecontrol.proto"; import "frameworks/base/libs/incident/proto/android/privacy.proto"; @@ -28,7 +29,8 @@ option java_multiple_files = true; message SurfaceAnimatorProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional string animation_adapter = 1; + reserved 1; // Was string animation_adapter = 1 optional .android.view.SurfaceControlProto leash = 2; optional bool animation_start_delayed = 3; + optional AnimationAdapterProto animation_adapter = 4; }
\ No newline at end of file diff --git a/core/proto/android/view/remote_animation_target.proto b/core/proto/android/view/remote_animation_target.proto new file mode 100644 index 000000000000..d5da0a9a7f73 --- /dev/null +++ b/core/proto/android/view/remote_animation_target.proto @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +option java_package = "android.app"; +option java_multiple_files = true; + +package android.view; + +import "frameworks/base/core/proto/android/app/window_configuration.proto"; +import "frameworks/base/core/proto/android/graphics/point.proto"; +import "frameworks/base/core/proto/android/graphics/rect.proto"; +import "frameworks/base/core/proto/android/view/surfacecontrol.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; + +/** Proto representation for RemoteAnimationTarget.java class. */ +message RemoteAnimationTargetProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 task_id = 1; + optional int32 mode = 2; + optional .android.view.SurfaceControlProto leash = 3; + optional bool is_translucent = 4; + optional .android.graphics.RectProto clip_rect = 5; + optional .android.graphics.RectProto contentInsets = 6; + optional int32 prefix_order_index = 7; + optional .android.graphics.PointProto position = 8; + optional .android.graphics.RectProto source_container_bounds = 9; + optional .android.app.WindowConfigurationProto window_configuration = 10; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f521e4b60602..9b11a33593bd 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2552,6 +2552,12 @@ <permission android:name="android.permission.MANAGE_APP_OPS_RESTRICTIONS" android:protectionLevel="signature|installer" /> + <!-- Allows an application to update the user app op modes. + Not for use by third party apps. + @hide --> + <permission android:name="android.permission.MANAGE_APP_OPS_MODES" + android:protectionLevel="signature|installer|verifier" /> + <!-- @SystemApi Allows an application to open windows that are for use by parts of the system user interface. <p>Not for use by third-party applications. @@ -3089,7 +3095,8 @@ <!-- Allows an application to collect usage infomation about brightness slider changes. <p>Not for use by third-party applications.</p> @hide - @SystemApi --> + @SystemApi + @TestApi --> <permission android:name="android.permission.BRIGHTNESS_SLIDER_USAGE" android:protectionLevel="signature|privileged|development" /> @@ -3102,7 +3109,8 @@ <!-- Allows an application to modify the display brightness configuration @hide - @SystemApi --> + @SystemApi + @TestApi --> <permission android:name="android.permission.CONFIGURE_DISPLAY_BRIGHTNESS" android:protectionLevel="signature|privileged|development" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index dc937e63c11e..6c0be1b24df1 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -148,16 +148,16 @@ <string name="CLIRPermanent">You can\'t change the caller ID setting.</string> <!-- Notification title to tell the user that data service is blocked by access control. --> - <string name="RestrictedOnDataTitle">No data service</string> + <string name="RestrictedOnDataTitle">No mobile data service</string> <!-- Notification title to tell the user that emergency calling is blocked by access control. --> - <string name="RestrictedOnEmergencyTitle">No emergency calling</string> + <string name="RestrictedOnEmergencyTitle">Emergency calling unavailable</string> <!-- Notification title to tell the user that normal service is blocked by access control. --> <string name="RestrictedOnNormalTitle">No voice service</string> <!-- Notification title to tell the user that all emergency and normal voice services are blocked by access control. --> - <string name="RestrictedOnAllVoiceTitle">No voice/emergency service</string> + <string name="RestrictedOnAllVoiceTitle">No voice service or emergency calling</string> <!-- Notification content to tell the user that voice/data/emergency service is blocked by access control. --> - <string name="RestrictedStateContent">Temporarily not offered by the mobile network at your location</string> + <string name="RestrictedStateContent">Temporarily turned off by your carrier</string> <!-- Displayed to tell the user that they should switch their network preference. --> <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach network</string> @@ -352,9 +352,6 @@ <!-- Work profile deleted notification--> <skip /> <!-- Shows up in the notification's title when the system deletes the work profile. [CHAR LIMIT=NONE] --> <string name="work_profile_deleted">Work profile deleted</string> - <!-- Content text for a notification. The Title of the notification is "Work profile deleted". - This says that the profile is deleted by the system as a result of the current profile owner gone missing. [CHAR LIMIT=100]--> - <string name="work_profile_deleted_description">Work profile deleted due to missing admin app</string> <!-- Content text for an expanded notification. The Title of the notification is "Work profile deleted". This further explains that the profile is deleted by the system as a result of the current profile admin gone missing. [CHAR LIMIT=NONE]--> <string name="work_profile_deleted_details">The work profile admin app is either missing or corrupted. @@ -2447,6 +2444,18 @@ <string name="more_item_label">More</string> <!-- Prepended to the shortcut for a menu item to indicate that the user should hold the MENU button together with the shortcut to invoke the item. For example, if the shortcut to open a new tab in browser is MENU and B together, then this would be prepended to the letter "B" --> <string name="prepend_shortcut_label">Menu+</string> + <!-- Prepended to the shortcut for a menu item to indicate that the user should hold the META key together with the shortcut to invoke the item. --> + <string name="menu_meta_shortcut_label">Meta+</string> + <!-- Prepended to the shortcut for a menu item to indicate that the user should hold the CTRL key together with the shortcut to invoke the item. --> + <string name="menu_ctrl_shortcut_label">Ctrl+</string> + <!-- Prepended to the shortcut for a menu item to indicate that the user should hold the ALT key together with the shortcut to invoke the item. --> + <string name="menu_alt_shortcut_label">Alt+</string> + <!-- Prepended to the shortcut for a menu item to indicate that the user should hold the SHIFT key together with the shortcut to invoke the item. --> + <string name="menu_shift_shortcut_label">Shift+</string> + <!-- Prepended to the shortcut for a menu item to indicate that the user should hold the SYM key together with the shortcut to invoke the item. --> + <string name="menu_sym_shortcut_label">Sym+</string> + <!-- Prepended to the shortcut for a menu item to indicate that the user should hold the FUNCTION key together with the shortcut to invoke the item. --> + <string name="menu_function_shortcut_label">Function+</string> <!-- Displayed in place of the regular shortcut letter when a menu item has Menu+space for the shortcut. --> <string name="menu_space_shortcut_label">space</string> <!-- Displayed in place of the regular shortcut letter when a menu item has Menu+enter for the shortcut. --> @@ -4880,10 +4889,16 @@ <!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) --> <string name="screenshot_edit">Edit</string> - <!-- Title for the notification channel notifying user of settings system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] --> + <!-- Title for the notification channel notifying user of settings system changes. [CHAR LIMIT=NONE] --> <string name="notification_channel_system_changes">System changes</string> + <!-- Title for the notification channel notifying user of do not disturb system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] --> + <string name="notification_channel_do_not_disturb">Do Not Disturb</string> + <!-- Title of notification indicating do not disturb visual interruption settings have changed when upgrading to P --> + <string name="zen_upgrade_notification_visd_title">Do Not Disturb is hiding notifications to help you focus</string> + <!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings --> + <string name="zen_upgrade_notification_visd_content">This is new behavior. Tap to change.</string> <!-- Title of notification indicating do not disturb settings have changed when upgrading to P --> - <string name="zen_upgrade_notification_title">Do Not Disturb is hiding notifications to help you focus</string> + <string name="zen_upgrade_notification_title">Do Not Disturb has changed</string> <!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings --> - <string name="zen_upgrade_notification_content">This is a new feature from the latest system update. Tap to change.</string> + <string name="zen_upgrade_notification_content">Tap to check what\'s blocked.</string> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 97116f54e7c9..55e91571c8c0 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -528,9 +528,15 @@ <java-symbol type="string" name="delete" /> <java-symbol type="string" name="deleteText" /> <java-symbol type="string" name="grant_permissions_header_text" /> + <java-symbol type="string" name="menu_alt_shortcut_label" /> + <java-symbol type="string" name="menu_ctrl_shortcut_label" /> <java-symbol type="string" name="menu_delete_shortcut_label" /> <java-symbol type="string" name="menu_enter_shortcut_label" /> + <java-symbol type="string" name="menu_function_shortcut_label" /> + <java-symbol type="string" name="menu_meta_shortcut_label" /> <java-symbol type="string" name="menu_space_shortcut_label" /> + <java-symbol type="string" name="menu_shift_shortcut_label" /> + <java-symbol type="string" name="menu_sym_shortcut_label" /> <java-symbol type="string" name="notification_title" /> <java-symbol type="string" name="permission_request_notification_with_subtitle" /> <java-symbol type="string" name="prepend_shortcut_label" /> @@ -3123,6 +3129,7 @@ <java-symbol type="string" name="notification_channel_usb" /> <java-symbol type="string" name="notification_channel_heavy_weight_app" /> <java-symbol type="string" name="notification_channel_system_changes" /> + <java-symbol type="string" name="notification_channel_do_not_disturb" /> <java-symbol type="string" name="config_defaultAutofillService" /> <java-symbol type="string" name="config_defaultTextClassifierPackage" /> @@ -3289,6 +3296,8 @@ <java-symbol type="string" name="zen_upgrade_notification_title" /> <java-symbol type="string" name="zen_upgrade_notification_content" /> + <java-symbol type="string" name="zen_upgrade_notification_visd_title" /> + <java-symbol type="string" name="zen_upgrade_notification_visd_content" /> <java-symbol type="string" name="config_managed_provisioning_package" /> diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml index 970a0f00bf5e..7b5ad9a42d00 100644 --- a/core/tests/coretests/AndroidTest.xml +++ b/core/tests/coretests/AndroidTest.xml @@ -14,15 +14,16 @@ limitations under the License. --> <configuration description="Runs Frameworks Core Tests."> - <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="FrameworksCoreTests.apk" /> <option name="test-file-name" value="BstatsTestApp.apk" /> </target_preparer> - - <option name="test-suite-tag" value="apct" /> <option name="test-tag" value="FrameworksCoreTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.frameworks.coretests" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> </test> </configuration> diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk index c3af6bd123b8..4642694d7b67 100644 --- a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk +++ b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk @@ -24,5 +24,6 @@ LOCAL_PACKAGE_NAME := BinderProxyCountingTestApp LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform +LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.mk b/core/tests/coretests/BinderProxyCountingTestService/Android.mk index 34016ed633b1..f852c7afeacd 100644 --- a/core/tests/coretests/BinderProxyCountingTestService/Android.mk +++ b/core/tests/coretests/BinderProxyCountingTestService/Android.mk @@ -24,5 +24,6 @@ LOCAL_PACKAGE_NAME := BinderProxyCountingTestService LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform +LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/BstatsTestApp/Android.mk b/core/tests/coretests/BstatsTestApp/Android.mk index e04536ba7499..a5872a5e5be9 100644 --- a/core/tests/coretests/BstatsTestApp/Android.mk +++ b/core/tests/coretests/BstatsTestApp/Android.mk @@ -30,4 +30,5 @@ LOCAL_CERTIFICATE := platform LOCAL_DEX_PREOPT := false LOCAL_PROGUARD_ENABLED := disabled -include $(BUILD_PACKAGE)
\ No newline at end of file +LOCAL_COMPATIBILITY_SUITE := device-tests +include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 22a261e35453..73fb7139cbd4 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -383,6 +383,7 @@ public class SettingsBackupTest { Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, Settings.Global.SYS_VDSO, Settings.Global.SYS_UIDCPUPOWER, + Settings.Global.SYS_TRACED, Settings.Global.FPS_DEVISOR, Settings.Global.TCP_DEFAULT_INIT_RWND, Settings.Global.TETHER_DUN_APN, diff --git a/core/tests/featureflagtests/AndroidTest.xml b/core/tests/featureflagtests/AndroidTest.xml index 44f9c3e37853..38c048ab061e 100644 --- a/core/tests/featureflagtests/AndroidTest.xml +++ b/core/tests/featureflagtests/AndroidTest.xml @@ -15,14 +15,16 @@ limitations under the License. --> <configuration description="Runs Frameworks Utility Tests."> - <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="FrameworksCoreFeatureFlagTests.apk" /> </target_preparer> - <option name="test-suite-tag" value="apct" /> <option name="test-tag" value="FrameworksCoreFeatureFlagTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.frameworks.coretests.featureflagtests" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> </test> </configuration> diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml index f06983559830..6507839a4288 100644 --- a/core/tests/overlaytests/device/AndroidTest.xml +++ b/core/tests/overlaytests/device/AndroidTest.xml @@ -17,8 +17,10 @@ <configuration description="Test module config for OverlayDeviceTests"> <option name="test-tag" value="OverlayDeviceTests" /> <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="OverlayDeviceTests.apk" /> <option name="test-file-name" value="OverlayDeviceTests_AppOverlayOne.apk" /> <option name="test-file-name" value="OverlayDeviceTests_AppOverlayTwo.apk" /> @@ -42,6 +44,5 @@ <test class="com.android.tradefed.testtype.AndroidJUnitTest"> <option name="package" value="com.android.overlaytest" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> </test> </configuration> diff --git a/core/tests/privacytests/AndroidTest.xml b/core/tests/privacytests/AndroidTest.xml index a43f48eb6e68..8098c1497865 100644 --- a/core/tests/privacytests/AndroidTest.xml +++ b/core/tests/privacytests/AndroidTest.xml @@ -14,12 +14,14 @@ limitations under the License. --> <configuration description="Runs Privacy Tests."> - <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="FrameworksPrivacyLibraryTests.apk" /> </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.frameworks.coretests.privacy" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> </test> -</configuration>
\ No newline at end of file +</configuration> diff --git a/core/tests/utiltests/AndroidTest.xml b/core/tests/utiltests/AndroidTest.xml index 65bb8decc332..270d7731a974 100644 --- a/core/tests/utiltests/AndroidTest.xml +++ b/core/tests/utiltests/AndroidTest.xml @@ -14,14 +14,16 @@ limitations under the License. --> <configuration description="Runs Frameworks Utility Tests."> - <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="FrameworksUtilTests.apk" /> </target_preparer> - <option name="test-suite-tag" value="apct" /> <option name="test-tag" value="FrameworksUtilTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.frameworks.utiltests" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> </test> </configuration> diff --git a/core/tests/webkit/AndroidTest.xml b/core/tests/webkit/AndroidTest.xml index 78cfa462beeb..4c50b7df3368 100644 --- a/core/tests/webkit/AndroidTest.xml +++ b/core/tests/webkit/AndroidTest.xml @@ -14,7 +14,9 @@ limitations under the License. --> <configuration description="Runs Frameworks WebView Loading Tests."> - <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="test-file-name" value="WebViewLoadingTests.apk" /> <option name="test-file-name" value="WebViewLoadingOnDiskTestApk.apk" /> <option name="test-file-name" value="WebViewLoadingFromApkTestApk.apk" /> @@ -24,6 +26,5 @@ <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.webkit.tests" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> </test> </configuration> diff --git a/core/tests/webkit/apk_with_native_libs/Android.mk b/core/tests/webkit/apk_with_native_libs/Android.mk index c51de6a7897e..e18a7e0df175 100644 --- a/core/tests/webkit/apk_with_native_libs/Android.mk +++ b/core/tests/webkit/apk_with_native_libs/Android.mk @@ -45,6 +45,7 @@ LOCAL_CFLAGS := $(MY_CFLAGS) LOCAL_SDK_VERSION := $(MY_SDK_VERSION) LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED) LOCAL_MULTILIB := $(MY_MULTILIB) +LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) @@ -65,5 +66,6 @@ LOCAL_CFLAGS := $(MY_CFLAGS) LOCAL_SDK_VERSION := $(MY_SDK_VERSION) LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED) LOCAL_MULTILIB := $(MY_MULTILIB) +LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml index fd1027c218d8..be0372deb14e 100644 --- a/data/etc/hiddenapi-package-whitelist.xml +++ b/data/etc/hiddenapi-package-whitelist.xml @@ -67,6 +67,7 @@ which apps should be allowed to access the entire private API. <hidden-api-whitelisted-app package="com.android.pacprocessor" /> <hidden-api-whitelisted-app package="com.android.phone" /> <hidden-api-whitelisted-app package="com.android.pmc" /> + <hidden-api-whitelisted-app package="com.android.printservice.recommendation" /> <hidden-api-whitelisted-app package="com.android.printspooler" /> <hidden-api-whitelisted-app package="com.android.providers.blockednumber" /> <hidden-api-whitelisted-app package="com.android.providers.contacts" /> diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java index 07df0454362c..5dc446391ec6 100644 --- a/graphics/java/android/graphics/BaseCanvas.java +++ b/graphics/java/android/graphics/BaseCanvas.java @@ -454,8 +454,7 @@ public abstract class BaseCanvas { throwIfHasHwBitmapInSwMode(paint); nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount, - x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */, - 0 /* measured text offset */); + x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */); } public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart, @@ -486,19 +485,16 @@ public abstract class BaseCanvas { char[] buf = TemporaryBuffer.obtain(contextLen); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); long measuredTextPtr = 0; - int measuredTextOffset = 0; if (text instanceof PrecomputedText) { PrecomputedText mt = (PrecomputedText) text; int paraIndex = mt.findParaIndex(start); if (end <= mt.getParagraphEnd(paraIndex)) { - // Only suppor the same paragraph. + // Only suppor the text in the same paragraph. measuredTextPtr = mt.getMeasuredParagraph(paraIndex).getNativePtr(); - measuredTextOffset = start - mt.getParagraphStart(paraIndex); } } nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len, - 0, contextLen, x, y, isRtl, paint.getNativeInstance(), - measuredTextPtr, measuredTextOffset); + 0, contextLen, x, y, isRtl, paint.getNativeInstance(), measuredTextPtr); TemporaryBuffer.recycle(buf); } } @@ -647,7 +643,7 @@ public abstract class BaseCanvas { private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, - long nativePrecomputedText, int measuredTextOffset); + long nativePrecomputedText); private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint); diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 44e7066c5c66..52d29e32e464 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -461,6 +461,11 @@ public final class Bitmap implements Parcelable { * * This configuration may be useful when using opaque bitmaps * that do not require high color fidelity. + * + * <p>Use this formula to pack into 16 bits:</p> + * <pre class="prettyprint"> + * short color = (R & 0x1f) << 11 | (G & 0x3f) << 5 | (B & 0x1f); + * </pre> */ RGB_565 (3), @@ -493,6 +498,11 @@ public final class Bitmap implements Parcelable { * * This configuration is very flexible and offers the best * quality. It should be used whenever possible. + * + * <p>Use this formula to pack into 32 bits:</p> + * <pre class="prettyprint"> + * int color = (A & 0xff) << 24 | (B & 0xff) << 16 | (G & 0xff) << 8 | (R & 0xff); + * </pre> */ ARGB_8888 (5), @@ -503,6 +513,11 @@ public final class Bitmap implements Parcelable { * * This configuration is particularly suited for wide-gamut and * HDR content. + * + * <p>Use this formula to pack into 64 bits:</p> + * <pre class="prettyprint"> + * long color = (A & 0xffff) << 48 | (B & 0xffff) << 32 | (G & 0xffff) << 16 | (R & 0xffff); + * </pre> */ RGBA_F16 (6), diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index f27c11dbf735..20c22b720717 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -167,10 +167,8 @@ public class Typeface { nativeSetDefault(t.native_instance); } - // TODO: Make this public API. (b/64852739) - /** @hide */ - @VisibleForTesting - public int getWeight() { + /** Returns the typeface's weight value */ + public @IntRange(from = 0, to = 1000) int getWeight() { return mWeight; } @@ -883,6 +881,15 @@ public class Typeface { } /** + * This method is used by supportlib-v27. + * TODO: Remove private API use in supportlib: http://b/72665240 + */ + private static Typeface createFromFamiliesWithDefault(FontFamily[] families, int weight, + int italic) { + return createFromFamiliesWithDefault(families, DEFAULT_FAMILY, weight, italic); + } + + /** * Create a new typeface from an array of font families, including * also the font families in the fallback list. * @param fallbackName the family name. If given families don't support characters, the diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 2b0b22df7edf..40b811d813fd 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -764,6 +764,13 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset, const SkPaint& paint, const SkPath& path, size_t start, size_t end) { + // Set align to left for drawing, as we don't want individual + // glyphs centered or right-aligned; the offsets take care of + // that portion of the alignment. + SkPaint paintCopy(paint); + paintCopy.setTextAlign(SkPaint::kLeft_Align); + SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); + const int N = end - start; SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform))); SkRSXform* xform = (SkRSXform*)storage.get(); @@ -788,7 +795,7 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, xform[i - start].fTy = pos.y() + tan.x() * y - halfWidth * tan.y(); } - this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint); + this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paintCopy); } // ---------------------------------------------------------------------------- diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index ad4c8be74d75..20543df85068 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -158,13 +158,13 @@ private: void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount, float x, float y, minikin::Bidi bidiFlags, const Paint& origPaint, - const Typeface* typeface, minikin::MeasuredText* mt, int mtOffset) { + const Typeface* typeface, minikin::MeasuredText* mt) { // minikin may modify the original paint Paint paint(origPaint); minikin::Layout layout = MinikinUtils::doLayout(&paint, bidiFlags, typeface, text, start, count, contextCount, - mt, mtOffset); + mt); x += MinikinUtils::xOffsetForTextAlign(&paint, layout); @@ -212,8 +212,7 @@ void Canvas::drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiF const Typeface* typeface) { Paint paintCopy(paint); minikin::Layout layout = - MinikinUtils::doLayout(&paintCopy, bidiFlags, typeface, text, 0, count, count, nullptr, - 0); + MinikinUtils::doLayout(&paintCopy, bidiFlags, typeface, text, 0, count, count, nullptr); hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path); // Set align to left for drawing, as we don't want individual diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index fabb8d2e4549..d04bb2e5ad03 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -270,7 +270,7 @@ public: */ void drawText(const uint16_t* text, int start, int count, int contextCount, float x, float y, minikin::Bidi bidiFlags, const Paint& origPaint, const Typeface* typeface, - minikin::MeasuredText* mt, int mtOffset); + minikin::MeasuredText* mt); void drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiFlags, const SkPath& path, float hOffset, float vOffset, const Paint& paint, diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp index a0d000dd2179..5b69bb78101f 100644 --- a/libs/hwui/hwui/MinikinUtils.cpp +++ b/libs/hwui/hwui/MinikinUtils.cpp @@ -49,8 +49,7 @@ minikin::MinikinPaint MinikinUtils::prepareMinikinPaint(const Paint* paint, minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, const uint16_t* buf, size_t start, - size_t count, size_t bufSize, minikin::MeasuredText* mt, - int mtOffset) { + size_t count, size_t bufSize, minikin::MeasuredText* mt) { minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface); minikin::Layout layout; @@ -62,15 +61,9 @@ minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFla if (mt == nullptr) { layout.doLayout(textBuf,range, bidiFlags, minikinPaint, startHyphen, endHyphen); - return layout; + } else { + mt->buildLayout(textBuf, range, minikinPaint, bidiFlags, startHyphen, endHyphen, &layout); } - - if (mt->buildLayout(textBuf, range, minikinPaint, bidiFlags, mtOffset, startHyphen, endHyphen, - &layout)) { - return layout; - } - - layout.doLayout(textBuf, range, bidiFlags, minikinPaint, startHyphen, endHyphen); return layout; } @@ -85,7 +78,8 @@ float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags, const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit); return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen, - endHyphen, advances, nullptr /* extent */); + endHyphen, advances, nullptr /* extent */, + nullptr /* layout pieces */); } bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) { diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h index 124fe4f81fbe..77dfbb21f7b5 100644 --- a/libs/hwui/hwui/MinikinUtils.h +++ b/libs/hwui/hwui/MinikinUtils.h @@ -45,7 +45,7 @@ public: ANDROID_API static minikin::Layout doLayout(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize, - minikin::MeasuredText* mt, int mtOffset); + minikin::MeasuredText* mt); ANDROID_API static float measureText(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, const uint16_t* buf, diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index 51cf772e8691..b99854e5af07 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -125,7 +125,7 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint SkPaint glyphPaint(paint); glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, minikin::Bidi::LTR, - glyphPaint, nullptr, nullptr /* measured text */, 0 /* measured text offset */); + glyphPaint, nullptr, nullptr /* measured text */); } void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint, diff --git a/media/OWNERS b/media/OWNERS index f198f4324fc8..3e9a25e93034 100644 --- a/media/OWNERS +++ b/media/OWNERS @@ -4,3 +4,4 @@ lajos@google.com marcone@google.com sungsoo@google.com wjia@google.com +jaewan@google.com diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java index b51c662539cf..40be018dc2c6 100644 --- a/media/java/android/media/MediaController2.java +++ b/media/java/android/media/MediaController2.java @@ -836,20 +836,30 @@ public class MediaController2 implements AutoCloseable { } /** - * Sets the index of current DataSourceDesc in the play list to be played. + * Skips to the item in the playlist. + * <p> + * This calls {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)}. * - * @param item the index of DataSourceDesc in the play list you want to play - * @throws IllegalArgumentException if the play list is null - * @throws NullPointerException if index is outside play list range + * @param item The item in the playlist you want to play */ public void skipToPlaylistItem(@NonNull MediaItem2 item) { mProvider.skipToPlaylistItem_impl(item); } + /** + * Skips to the previous item in the playlist. + * <p> + * This calls {@link MediaPlaylistAgent#skipToPreviousItem()}. + */ public void skipToPreviousItem() { mProvider.skipToPreviousItem_impl(); } + /** + * Skips to the next item in the playlist. + * <p> + * This calls {@link MediaPlaylistAgent#skipToNextItem()}. + */ public void skipToNextItem() { mProvider.skipToNextItem_impl(); } diff --git a/media/java/android/media/MediaPlaylistAgent.java b/media/java/android/media/MediaPlaylistAgent.java index 1d7520ff9f0d..65884743523a 100644 --- a/media/java/android/media/MediaPlaylistAgent.java +++ b/media/java/android/media/MediaPlaylistAgent.java @@ -266,10 +266,16 @@ public abstract class MediaPlaylistAgent { mProvider.skipToPlaylistItem_impl(item); } + /** + * Skips to the previous item in the playlist. + */ public void skipToPreviousItem() { mProvider.skipToPreviousItem_impl(); } + /** + * Skips to the next item in the playlist. + */ public void skipToNextItem() { mProvider.skipToNextItem_impl(); } diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java index e60c5f9b3b8c..a7aa3a7fe64c 100644 --- a/media/java/android/media/MediaSession2.java +++ b/media/java/android/media/MediaSession2.java @@ -182,16 +182,6 @@ public class MediaSession2 implements AutoCloseable { public static final int COMMAND_CODE_PLAYBACK_ADJUST_VOLUME = 11; /** - * Command code for {@link MediaController2#setPlaylistParams(PlaylistParams)}. - * <p> - * Command would be sent directly to the player if the session doesn't reject the request - * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}. - * @hide - */ - // TODO(jaewan): Remove (b/74116823) - public static final int COMMAND_CODE_PLAYBACK_SET_PLAYLIST_PARAMS = 12; - - /** * Command code for {@link MediaController2#skipToPlaylistItem(MediaItem2)}. * <p> * Command would be sent directly to the playlist agent if the session doesn't reject the @@ -314,6 +304,13 @@ public class MediaSession2 implements AutoCloseable { public static final int COMMAND_CODE_PREPARE_FROM_SEARCH = 27; /** + * Command code for {@link MediaController2#setRating(String, Rating2)}. + * @hide + */ + // TODO(jaewan): Unhide + public static final int COMMAND_CODE_SET_RATING = 29; + + /** * Command code for {@link MediaBrowser2} specific functions that allows navigation and search * from the {@link MediaLibraryService2}. This would be ignored for a {@link MediaSession2}, * not {@link android.media.MediaLibraryService2.MediaLibrarySession}. @@ -325,11 +322,6 @@ public class MediaSession2 implements AutoCloseable { /** * @hide */ - public static final int COMMAND_CODE_MAX = 28; - - /** - * @hide - */ @IntDef({ERROR_CODE_UNKNOWN_ERROR, ERROR_CODE_APP_ERROR, ERROR_CODE_NOT_SUPPORTED, ERROR_CODE_AUTHENTICATION_EXPIRED, ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED, ERROR_CODE_CONCURRENT_STREAM_LIMIT, ERROR_CODE_PARENTAL_CONTROL_RESTRICTED, @@ -452,6 +444,13 @@ public class MediaSession2 implements AutoCloseable { .createMediaSession2Command(this, COMMAND_CODE_CUSTOM, action, extras); } + /** + * @hide + */ + public CommandProvider getProvider() { + return mProvider; + } + public int getCommandCode() { return mProvider.getCommandCode_impl(); } @@ -510,6 +509,13 @@ public class MediaSession2 implements AutoCloseable { .createMediaSession2CommandGroup(context, this, others); } + /** + * @hide + */ + public CommandGroup(@NonNull CommandGroupProvider provider) { + mProvider = provider; + } + public void addCommand(@NonNull Command command) { mProvider.addCommand_impl(command); } @@ -622,7 +628,6 @@ public class MediaSession2 implements AutoCloseable { * @see #COMMAND_CODE_PLAYBACK_REWIND * @see #COMMAND_CODE_PLAYBACK_SEEK_TO * @see #COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM - * @see #COMMAND_CODE_PLAYBACK_SET_PLAYLIST_PARAMS * @see #COMMAND_CODE_PLAYLIST_ADD_ITEM * @see #COMMAND_CODE_PLAYLIST_REMOVE_ITEM * @see #COMMAND_CODE_PLAYLIST_GET_LIST @@ -1774,20 +1779,41 @@ public class MediaSession2 implements AutoCloseable { } /** - * Skip to the item in the play list. + * Skips to the item in the playlist. + * <p> + * This calls {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)} and the behavior depends + * on the playlist agent implementation, especially with the shuffle/repeat mode. * - * @param item item in the play list you want to play - * @throws IllegalArgumentException if the play list is null - * @throws NullPointerException if index is outside play list range + * @param item The item in the playlist you want to play + * @see #getShuffleMode() + * @see #getRepeatMode() */ public void skipToPlaylistItem(@NonNull MediaItem2 item) { mProvider.skipToPlaylistItem_impl(item); } + /** + * Skips to the previous item. + * <p> + * This calls {@link MediaPlaylistAgent#skipToPreviousItem()} and the behavior depends on the + * playlist agent implementation, especially with the shuffle/repeat mode. + * + * @see #getShuffleMode() + * @see #getRepeatMode() + **/ public void skipToPreviousItem() { mProvider.skipToPreviousItem_impl(); } + /** + * Skips to the next item. + * <p> + * This calls {@link MediaPlaylistAgent#skipToNextItem()} and the behavior depends on the + * playlist agent implementation, especially with the shuffle/repeat mode. + * + * @see #getShuffleMode() + * @see #getRepeatMode() + */ public void skipToNextItem() { mProvider.skipToNextItem_impl(); } diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java index 2b6d09f9b72e..70816782541d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java @@ -19,6 +19,7 @@ package com.android.settingslib.fuelgauge; import android.os.IDeviceIdleController; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.support.annotation.VisibleForTesting; import android.util.ArraySet; import android.util.Log; @@ -37,6 +38,7 @@ public class PowerWhitelistBackend { private final IDeviceIdleController mDeviceIdleService; private final ArraySet<String> mWhitelistedApps = new ArraySet<>(); private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>(); + private final ArraySet<String> mSysWhitelistedAppsExceptIdle = new ArraySet<>(); public PowerWhitelistBackend() { mDeviceIdleService = IDeviceIdleController.Stub.asInterface( @@ -62,6 +64,10 @@ public class PowerWhitelistBackend { return mWhitelistedApps.contains(pkg); } + public boolean isSysWhitelistedExceptIdle(String pkg) { + return mSysWhitelistedAppsExceptIdle.contains(pkg); + } + public void addApp(String pkg) { try { mDeviceIdleService.addPowerSaveWhitelistApp(pkg); @@ -83,6 +89,7 @@ public class PowerWhitelistBackend { @VisibleForTesting public void refreshList() { mSysWhitelistedApps.clear(); + mSysWhitelistedAppsExceptIdle.clear(); mWhitelistedApps.clear(); try { String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist(); @@ -93,6 +100,11 @@ public class PowerWhitelistBackend { for (String app : sysWhitelistedApps) { mSysWhitelistedApps.add(app); } + String[] sysWhitelistedAppsExceptIdle = + mDeviceIdleService.getSystemPowerWhitelistExceptIdle(); + for (String app : sysWhitelistedAppsExceptIdle) { + mSysWhitelistedAppsExceptIdle.add(app); + } } catch (RemoteException e) { Log.w(TAG, "Unable to reach IDeviceIdleController", e); } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 2482095af419..085e1123d67e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -563,8 +563,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro // If there were no scan results, create an AP for the currently connected network (if // it exists). - // TODO(sghuman): Investigate if this works for an ephemeral (auto-connected) network - // when there are no scan results, as it may not have a valid WifiConfiguration + // TODO(b/b/73076869): Add support for passpoint (ephemeral) networks if (accessPoints.isEmpty() && connectionConfig != null) { AccessPoint activeAp = new AccessPoint(mContext, connectionConfig); activeAp.update(connectionConfig, mLastInfo, mLastNetworkInfo); diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index 54c02a22e79f..e435a72861da 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -18,9 +18,11 @@ package com.android.settingslib.wifi; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -50,6 +52,7 @@ import android.text.format.DateUtils; import android.text.style.TtsSpan; import com.android.settingslib.R; +import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.wifi.AccessPoint.Speed; import org.junit.Before; @@ -61,6 +64,7 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.concurrent.CountDownLatch; @SmallTest @RunWith(AndroidJUnit4.class) @@ -79,6 +83,8 @@ public class AccessPointTest { private Context mContext; @Mock private RssiCurve mockBadgeCurve; @Mock private WifiNetworkScoreCache mockWifiNetworkScoreCache; + public static final int NETWORK_ID = 123; + public static final int DEFAULT_RSSI = -55; private static ScanResult createScanResult(String ssid, String bssid, int rssi) { ScanResult scanResult = new ScanResult(); @@ -753,16 +759,15 @@ public class AccessPointTest { assertThat(ap.update(config, wifiInfo, newInfo)).isFalse(); } @Test - public void testUpdateWithConfigChangeOnly_returnsFalseButInvokesListener() { - int networkId = 123; - int rssi = -55; + public void testUpdateWithConfigChangeOnly_returnsFalseButInvokesListener() + throws InterruptedException { WifiConfiguration config = new WifiConfiguration(); - config.networkId = networkId; + config.networkId = NETWORK_ID; config.numNoInternetAccessReports = 1; WifiInfo wifiInfo = new WifiInfo(); - wifiInfo.setNetworkId(networkId); - wifiInfo.setRssi(rssi); + wifiInfo.setNetworkId(NETWORK_ID); + wifiInfo.setRssi(DEFAULT_RSSI); NetworkInfo networkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", ""); @@ -770,8 +775,8 @@ public class AccessPointTest { AccessPoint ap = new TestAccessPointBuilder(mContext) .setNetworkInfo(networkInfo) - .setNetworkId(networkId) - .setRssi(rssi) + .setNetworkId(NETWORK_ID) + .setRssi(DEFAULT_RSSI) .setWifiInfo(wifiInfo) .build(); @@ -781,18 +786,131 @@ public class AccessPointTest { config.validatedInternetAccess = true; assertThat(ap.update(newConfig, wifiInfo, networkInfo)).isFalse(); + + // Wait for MainHandler to process callback + CountDownLatch latch = new CountDownLatch(1); + ThreadUtils.postOnMainThread(latch::countDown); + + latch.await(); verify(mockListener).onAccessPointChanged(ap); } @Test + public void testConnectionInfo_doesNotThrowNPE_ifListenerIsNulledWhileAwaitingExecution() + throws InterruptedException { + WifiConfiguration config = new WifiConfiguration(); + config.networkId = NETWORK_ID; + config.numNoInternetAccessReports = 1; + + WifiInfo wifiInfo = new WifiInfo(); + wifiInfo.setNetworkId(NETWORK_ID); + wifiInfo.setRssi(DEFAULT_RSSI); + + NetworkInfo networkInfo = + new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", ""); + networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", ""); + + AccessPoint ap = new TestAccessPointBuilder(mContext) + .setNetworkInfo(networkInfo) + .setNetworkId(NETWORK_ID) + .setRssi(DEFAULT_RSSI) + .setWifiInfo(wifiInfo) + .build(); + + WifiConfiguration newConfig = new WifiConfiguration(config); + config.validatedInternetAccess = true; + + performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution( + ap, () -> assertThat(ap.update(newConfig, wifiInfo, networkInfo)).isFalse()); + + } + + private void performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution( + AccessPoint ap, Runnable r) { + AccessPoint.AccessPointListener mockListener = mock(AccessPoint.AccessPointListener.class); + ap.setListener(mockListener); + + // Put a latch on the MainHandler to prevent the callback from being invoked instantly + CountDownLatch latch1 = new CountDownLatch(1); + ThreadUtils.postOnMainThread(() -> { + try{ + latch1.await(); + } catch (InterruptedException e) { + fail("Interruped Exception thrown while awaiting latch countdown"); + } + }); + + r.run(); + + ap.setListener(null); + latch1.countDown(); + + // The second latch ensures the previously posted listener invocation has processed on the + // main thread. + CountDownLatch latch2 = new CountDownLatch(1); + ThreadUtils.postOnMainThread(latch2::countDown); + + try{ + latch2.await(); + } catch (InterruptedException e) { + fail("Interruped Exception thrown while awaiting latch countdown"); + } + } + + @Test + public void testUpdateScanResults_doesNotThrowNPE_ifListenerIsNulledWhileAwaitingExecution() + throws InterruptedException { + String ssid = "ssid"; + int newRssi = -80; + AccessPoint ap = new TestAccessPointBuilder(mContext).setSsid(ssid).build(); + + ScanResult scanResult = new ScanResult(); + scanResult.SSID = ssid; + scanResult.level = newRssi; + scanResult.BSSID = "bssid"; + scanResult.timestamp = SystemClock.elapsedRealtime() * 1000; + scanResult.capabilities = ""; + + performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution( + ap, () -> ap.setScanResults(Collections.singletonList(scanResult))); + } + + @Test + public void testUpdateConfig_doesNotThrowNPE_ifListenerIsNulledWhileAwaitingExecution() + throws InterruptedException { + WifiConfiguration config = new WifiConfiguration(); + config.networkId = NETWORK_ID; + config.numNoInternetAccessReports = 1; + + WifiInfo wifiInfo = new WifiInfo(); + wifiInfo.setNetworkId(NETWORK_ID); + wifiInfo.setRssi(DEFAULT_RSSI); + + NetworkInfo networkInfo = + new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", ""); + networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", ""); + + AccessPoint ap = new TestAccessPointBuilder(mContext) + .setNetworkInfo(networkInfo) + .setNetworkId(NETWORK_ID) + .setRssi(DEFAULT_RSSI) + .setWifiInfo(wifiInfo) + .build(); + + WifiConfiguration newConfig = new WifiConfiguration(config); + config.validatedInternetAccess = true; + + performGivenUpdateAndThenNullListenerBeforeResumingMainHandlerExecution( + ap, () -> ap.update(newConfig)); + } + + @Test public void testUpdateWithNullWifiConfiguration_doesNotThrowNPE() { - int networkId = 123; - int rssi = -55; WifiConfiguration config = new WifiConfiguration(); - config.networkId = networkId; + config.networkId = NETWORK_ID; WifiInfo wifiInfo = new WifiInfo(); - wifiInfo.setNetworkId(networkId); - wifiInfo.setRssi(rssi); + wifiInfo.setNetworkId(NETWORK_ID); + wifiInfo.setRssi(DEFAULT_RSSI); NetworkInfo networkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", ""); @@ -800,8 +918,8 @@ public class AccessPointTest { AccessPoint ap = new TestAccessPointBuilder(mContext) .setNetworkInfo(networkInfo) - .setNetworkId(networkId) - .setRssi(rssi) + .setNetworkId(NETWORK_ID) + .setRssi(DEFAULT_RSSI) .setWifiInfo(wifiInfo) .build(); @@ -847,34 +965,34 @@ public class AccessPointTest { .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve2)); ap.update( - mockWifiNetworkScoreCache, true /* scoringUiEnabled */, MAX_SCORE_CACHE_AGE_MILLIS); + mockWifiNetworkScoreCache, true /* scoringUiEnabled */, MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSpeed()).isEqualTo(speed1); } @Test public void testSpeedLabelFallbackScoreIgnoresNullCurves() { - int rssi = -55; String bssid = "00:00:00:00:00:00"; - int networkId = 123; WifiInfo info = new WifiInfo(); - info.setRssi(rssi); + info.setRssi(DEFAULT_RSSI); info.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID)); info.setBSSID(bssid); - info.setNetworkId(networkId); + info.setNetworkId(NETWORK_ID); ArrayList<ScanResult> scanResults = new ArrayList<>(); - ScanResult scanResultUnconnected = createScanResult(TEST_SSID, "11:11:11:11:11:11", rssi); + ScanResult scanResultUnconnected = + createScanResult(TEST_SSID, "11:11:11:11:11:11", DEFAULT_RSSI); scanResults.add(scanResultUnconnected); - ScanResult scanResultConnected = createScanResult(TEST_SSID, bssid, rssi); + ScanResult scanResultConnected = + createScanResult(TEST_SSID, bssid, DEFAULT_RSSI); scanResults.add(scanResultConnected); AccessPoint ap = new TestAccessPointBuilder(mContext) .setActive(true) - .setNetworkId(networkId) + .setNetworkId(NETWORK_ID) .setSsid(TEST_SSID) .setScanResults(scanResults) .setWifiInfo(info) diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java index ca965f38f639..7fb4dc544d28 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java @@ -721,7 +721,7 @@ public class WifiTrackerTest { // mStaleAccessPoints is true verify(mockWifiListenerExecutor, never()).onAccessPointsChanged(); - assertThat(tracker.getAccessPoints().size()).isEqualTo(1); + assertThat(tracker.getAccessPoints()).hasSize(1); assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue(); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java index c6a1428fa34e..5a123af02ca4 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java @@ -48,6 +48,7 @@ public class PowerWhitelistBackendTest { MockitoAnnotations.initMocks(this); doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist(); doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist(); + doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle(); doNothing().when(mDeviceIdleService).addPowerSaveWhitelistApp(anyString()); doNothing().when(mDeviceIdleService).removePowerSaveWhitelistApp(anyString()); mPowerWhitelistBackend = new PowerWhitelistBackend(mDeviceIdleService); @@ -88,6 +89,15 @@ public class PowerWhitelistBackendTest { assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_ONE)).isTrue(); assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_TWO)).isFalse(); assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse(); + } + + @Test + public void testIsSystemWhitelistedExceptIdle() throws Exception { + doReturn(new String[]{PACKAGE_TWO}).when( + mDeviceIdleService).getSystemPowerWhitelistExceptIdle(); + mPowerWhitelistBackend.refreshList(); + assertThat(mPowerWhitelistBackend.isSysWhitelistedExceptIdle(PACKAGE_ONE)).isFalse(); + assertThat(mPowerWhitelistBackend.isSysWhitelistedExceptIdle(PACKAGE_TWO)).isTrue(); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index cfcfb95b0f88..4530f8062f0d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -40,6 +40,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Global; import android.provider.Settings.Secure; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; @@ -2594,15 +2595,26 @@ class DatabaseHelper extends SQLiteOpenHelper { loadSetting(stmt, Settings.Global.CALL_AUTO_RETRY, 0); // Set the preferred network mode to target desired value or Default - // value defined in RILConstants - int type; - type = RILConstants.PREFERRED_NETWORK_MODE; - loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, type); + // value defined in system property + String val = ""; + String mode; + for (int phoneId = 0; + phoneId < TelephonyManager.getDefault().getPhoneCount(); phoneId++) { + mode = TelephonyManager.getTelephonyProperty(phoneId, + "ro.telephony.default_network", + Integer.toString(RILConstants.PREFERRED_NETWORK_MODE)); + if (phoneId == 0) { + val = mode; + } else { + val = val + "," + mode; + } + } + loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, val); // Set the preferred cdma subscription source to target desired value or default // value defined in Phone - type = SystemProperties.getInt("ro.telephony.default_cdma_sub", - Phone.PREFERRED_CDMA_SUBSCRIPTION); + int type = SystemProperties.getInt("ro.telephony.default_cdma_sub", + Phone.PREFERRED_CDMA_SUBSCRIPTION); loadSetting(stmt, Settings.Global.CDMA_SUBSCRIPTION_MODE, type); loadIntegerSetting(stmt, Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index ccb4d8c866da..53cff4e84549 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -39,19 +39,15 @@ class SettingsProtoDumpUtil { SettingsState globalSettings = settingsRegistry.getSettingsLocked( SettingsProvider.SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM); if (globalSettings != null) { - long globalSettingsToken = proto.start(SettingsServiceDumpProto.GLOBAL_SETTINGS); - dumpProtoGlobalSettingsLocked(globalSettings, proto); - proto.end(globalSettingsToken); + dumpProtoGlobalSettingsLocked(proto, SettingsServiceDumpProto.GLOBAL_SETTINGS, globalSettings); } // Per-user settings SparseBooleanArray users = settingsRegistry.getKnownUsersLocked(); final int userCount = users.size(); for (int i = 0; i < userCount; i++) { - long userSettingsToken = proto.start(SettingsServiceDumpProto.USER_SETTINGS); - dumpProtoUserSettingsLocked( - settingsRegistry, UserHandle.of(users.keyAt(i)), proto); - proto.end(userSettingsToken); + dumpProtoUserSettingsLocked(proto, SettingsServiceDumpProto.USER_SETTINGS, + settingsRegistry, UserHandle.of(users.keyAt(i))); } } @@ -63,30 +59,33 @@ class SettingsProtoDumpUtil { * @param proto The proto buf stream to dump to */ private static void dumpProtoUserSettingsLocked( + @NonNull ProtoOutputStream proto, + long fieldId, SettingsProvider.SettingsRegistry settingsRegistry, - @NonNull UserHandle user, - @NonNull ProtoOutputStream proto) { + @NonNull UserHandle user) { + final long token = proto.start(fieldId); + proto.write(UserSettingsProto.USER_ID, user.getIdentifier()); SettingsState secureSettings = settingsRegistry.getSettingsLocked( SettingsProvider.SETTINGS_TYPE_SECURE, user.getIdentifier()); if (secureSettings != null) { - long secureSettingsToken = proto.start(UserSettingsProto.SECURE_SETTINGS); - dumpProtoSecureSettingsLocked(secureSettings, proto); - proto.end(secureSettingsToken); + dumpProtoSecureSettingsLocked(proto, UserSettingsProto.SECURE_SETTINGS, secureSettings); } SettingsState systemSettings = settingsRegistry.getSettingsLocked( SettingsProvider.SETTINGS_TYPE_SYSTEM, user.getIdentifier()); if (systemSettings != null) { - long systemSettingsToken = proto.start(UserSettingsProto.SYSTEM_SETTINGS); - dumpProtoSystemSettingsLocked(systemSettings, proto); - proto.end(systemSettingsToken); + dumpProtoSystemSettingsLocked(proto, UserSettingsProto.SYSTEM_SETTINGS, systemSettings); } + + proto.end(token); } private static void dumpProtoGlobalSettingsLocked( - @NonNull SettingsState s, @NonNull ProtoOutputStream p) { + @NonNull ProtoOutputStream p, long fieldId, @NonNull SettingsState s) { + final long token = p.start(fieldId); + s.dumpHistoricalOperations(p, GlobalSettingsProto.HISTORICAL_OPERATIONS); // This uses the same order as in Settings.Global. @@ -102,6 +101,11 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.THEATER_MODE_ON, GlobalSettingsProto.THEATER_MODE_ON); + // RADIO_BLUETOOTH is just a constant and not an actual setting. + // RADIO_WIFI is just a constant and not an actual setting. + // RADIO_WIMAX is just a constant and not an actual setting. + // RADIO_CELL is just a constant and not an actual setting. + // RADIO_NFC is just a constant and not an actual setting. dumpSetting(s, p, Settings.Global.AIRPLANE_MODE_RADIOS, GlobalSettingsProto.AIRPLANE_MODE_RADIOS); @@ -253,6 +257,9 @@ class SettingsProtoDumpUtil { Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, GlobalSettingsProto.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED); dumpSetting(s, p, + Settings.Global.PRIV_APP_OOB_ENABLED, + GlobalSettingsProto.PRIV_APP_OOB_ENABLED); + dumpSetting(s, p, Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS, GlobalSettingsProto.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS); dumpSetting(s, p, @@ -343,6 +350,9 @@ class SettingsProtoDumpUtil { Settings.Global.NETWORK_SCORER_APP, GlobalSettingsProto.NETWORK_SCORER_APP); dumpSetting(s, p, + Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE, + GlobalSettingsProto.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE); + dumpSetting(s, p, Settings.Global.NITZ_UPDATE_DIFF, GlobalSettingsProto.NITZ_UPDATE_DIFF); dumpSetting(s, p, @@ -499,6 +509,9 @@ class SettingsProtoDumpUtil { Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, GlobalSettingsProto.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON); dumpSetting(s, p, + Settings.Global.WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON, + GlobalSettingsProto.WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON); + dumpSetting(s, p, Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON, GlobalSettingsProto.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON); dumpSetting(s, p, @@ -523,6 +536,9 @@ class SettingsProtoDumpUtil { Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, GlobalSettingsProto.WIFI_SCAN_ALWAYS_AVAILABLE); dumpSetting(s, p, + Settings.Global.SOFT_AP_TIMEOUT_ENABLED, + GlobalSettingsProto.SOFT_AP_TIMEOUT_ENABLED); + dumpSetting(s, p, Settings.Global.WIFI_WAKEUP_ENABLED, GlobalSettingsProto.WIFI_WAKEUP_ENABLED); dumpSetting(s, p, @@ -532,6 +548,9 @@ class SettingsProtoDumpUtil { Settings.Global.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS, GlobalSettingsProto.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS); dumpSetting(s, p, + Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS, + GlobalSettingsProto.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS); + dumpSetting(s, p, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, GlobalSettingsProto.NETWORK_RECOMMENDATIONS_ENABLED); dumpSetting(s, p, @@ -544,12 +563,27 @@ class SettingsProtoDumpUtil { Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, GlobalSettingsProto.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS); dumpSetting(s, p, - Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS, - GlobalSettingsProto.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS); - dumpSetting(s, p, Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, GlobalSettingsProto.BLE_SCAN_ALWAYS_AVAILABLE); dumpSetting(s, p, + Settings.Global.BLE_SCAN_LOW_POWER_WINDOW_MS, + GlobalSettingsProto.BLE_SCAN_LOW_POWER_WINDOW_MS); + dumpSetting(s, p, + Settings.Global.BLE_SCAN_BALANCED_WINDOW_MS, + GlobalSettingsProto.BLE_SCAN_BALANCED_WINDOW_MS); + dumpSetting(s, p, + Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS, + GlobalSettingsProto.BLE_SCAN_LOW_LATENCY_WINDOW_MS); + dumpSetting(s, p, + Settings.Global.BLE_SCAN_LOW_POWER_INTERVAL_MS, + GlobalSettingsProto.BLE_SCAN_LOW_POWER_INTERVAL_MS); + dumpSetting(s, p, + Settings.Global.BLE_SCAN_BALANCED_INTERVAL_MS, + GlobalSettingsProto.BLE_SCAN_BALANCED_INTERVAL_MS); + dumpSetting(s, p, + Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS, + GlobalSettingsProto.BLE_SCAN_LOW_LATENCY_INTERVAL_MS); + dumpSetting(s, p, Settings.Global.WIFI_SAVED_STATE, GlobalSettingsProto.WIFI_SAVED_STATE); dumpSetting(s, p, @@ -645,12 +679,12 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.DROPBOX_RESERVE_PERCENT, GlobalSettingsProto.DROPBOX_RESERVE_PERCENT); - dumpSetting(s, p, + dumpRepeatedSetting(s, p, Settings.Global.DROPBOX_TAG_PREFIX, - GlobalSettingsProto.DROPBOX_TAG_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.DROPBOX_SETTINGS); + dumpRepeatedSetting(s, p, Settings.Global.ERROR_LOGCAT_PREFIX, - GlobalSettingsProto.ERROR_LOGCAT_PREFIX); + GlobalSettingsProto.ERROR_LOGCAT_LINES); dumpSetting(s, p, Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL, GlobalSettingsProto.SYS_FREE_STORAGE_LOG_INTERVAL); @@ -756,42 +790,42 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.PRIVATE_DNS_SPECIFIER, GlobalSettingsProto.PRIVATE_DNS_SPECIFIER); - dumpSetting(s, p, + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_HEADSET_PRIORITY_PREFIX, - GlobalSettingsProto.BLUETOOTH_HEADSET_PRIORITY_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_HEADSET_PRIORITIES); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX, - GlobalSettingsProto.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_A2DP_SINK_PRIORITIES); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX, - GlobalSettingsProto.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_A2DP_SRC_PRIORITIES); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX, - GlobalSettingsProto.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX, - GlobalSettingsProto.BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX, - GlobalSettingsProto.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_INPUT_DEVICE_PRIORITIES); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_MAP_PRIORITY_PREFIX, - GlobalSettingsProto.BLUETOOTH_MAP_PRIORITY_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_MAP_PRIORITIES); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX, - GlobalSettingsProto.BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_MAP_CLIENT_PRIORITIES); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX, - GlobalSettingsProto.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_PBAP_CLIENT_PRIORITIES); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_SAP_PRIORITY_PREFIX, - GlobalSettingsProto.BLUETOOTH_SAP_PRIORITY_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_SAP_PRIORITIES); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX, - GlobalSettingsProto.BLUETOOTH_PAN_PRIORITY_PREFIX); - dumpSetting(s, p, + GlobalSettingsProto.BLUETOOTH_PAN_PRIORITIES); + dumpRepeatedSetting(s, p, Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX, - GlobalSettingsProto.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX); + GlobalSettingsProto.BLUETOOTH_HEARING_AID_PRIORITIES); dumpSetting(s, p, Settings.Global.ACTIVITY_MANAGER_CONSTANTS, GlobalSettingsProto.ACTIVITY_MANAGER_CONSTANTS); @@ -802,12 +836,36 @@ class SettingsProtoDumpUtil { Settings.Global.BATTERY_SAVER_CONSTANTS, GlobalSettingsProto.BATTERY_SAVER_CONSTANTS); dumpSetting(s, p, + Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS, + GlobalSettingsProto.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS); + dumpSetting(s, p, + Settings.Global.BATTERY_TIP_CONSTANTS, + GlobalSettingsProto.BATTERY_TIP_CONSTANTS); + dumpSetting(s, p, Settings.Global.ANOMALY_DETECTION_CONSTANTS, GlobalSettingsProto.ANOMALY_DETECTION_CONSTANTS); dumpSetting(s, p, + Settings.Global.ANOMALY_CONFIG_VERSION, + GlobalSettingsProto.ANOMALY_CONFIG_VERSION); + dumpSetting(s, p, + Settings.Global.ANOMALY_CONFIG, + GlobalSettingsProto.ANOMALY_CONFIG); + dumpSetting(s, p, Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS, GlobalSettingsProto.ALWAYS_ON_DISPLAY_CONSTANTS); dumpSetting(s, p, + Settings.Global.SYS_VDSO, + GlobalSettingsProto.SYS_VDSO); + dumpSetting(s, p, + Settings.Global.SYS_UIDCPUPOWER, + GlobalSettingsProto.SYS_UIDCPUPOWER); + dumpSetting(s, p, + Settings.Global.FPS_DEVISOR, + GlobalSettingsProto.FPS_DIVISOR); + dumpSetting(s, p, + Settings.Global.DISPLAY_PANEL_LPM, + GlobalSettingsProto.DISPLAY_PANEL_LPM); + dumpSetting(s, p, Settings.Global.APP_IDLE_CONSTANTS, GlobalSettingsProto.APP_IDLE_CONSTANTS); dumpSetting(s, p, @@ -829,6 +887,42 @@ class SettingsProtoDumpUtil { Settings.Global.TEXT_CLASSIFIER_CONSTANTS, GlobalSettingsProto.TEXT_CLASSIFIER_CONSTANTS); dumpSetting(s, p, + Settings.Global.BATTERY_STATS_CONSTANTS, + GlobalSettingsProto.BATTERY_STATS_CONSTANTS); + dumpSetting(s, p, + Settings.Global.SYNC_MANAGER_CONSTANTS, + GlobalSettingsProto.SYNC_MANAGER_CONSTANTS); + dumpSetting(s, p, + Settings.Global.APP_STANDBY_ENABLED, + GlobalSettingsProto.APP_STANDBY_ENABLED); + dumpSetting(s, p, + Settings.Global.APP_AUTO_RESTRICTION_ENABLED, + GlobalSettingsProto.APP_AUTO_RESTRICTION_ENABLED); + dumpSetting(s, p, + Settings.Global.FORCED_APP_STANDBY_ENABLED, + GlobalSettingsProto.FORCED_APP_STANDBY_ENABLED); + dumpSetting(s, p, + Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, + GlobalSettingsProto.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED); + dumpSetting(s, p, + Settings.Global.OFF_BODY_RADIOS_OFF_FOR_SMALL_BATTERY_ENABLED, + GlobalSettingsProto.OFF_BODY_RADIOS_OFF_FOR_SMALL_BATTERY_ENABLED); + dumpSetting(s, p, + Settings.Global.OFF_BODY_RADIOS_OFF_DELAY_MS, + GlobalSettingsProto.OFF_BODY_RADIOS_OFF_DELAY_MS); + dumpSetting(s, p, + Settings.Global.WIFI_ON_WHEN_PROXY_DISCONNECTED, + GlobalSettingsProto.WIFI_ON_WHEN_PROXY_DISCONNECTED); + dumpSetting(s, p, + Settings.Global.TIME_ONLY_MODE_ENABLED, + GlobalSettingsProto.TIME_ONLY_MODE_ENABLED); + dumpSetting(s, p, + Settings.Global.NETWORK_WATCHLIST_ENABLED, + GlobalSettingsProto.NETWORK_WATCHLIST_ENABLED); + dumpSetting(s, p, + Settings.Global.KEEP_PROFILE_IN_BACKGROUND, + GlobalSettingsProto.KEEP_PROFILE_IN_BACKGROUND); + dumpSetting(s, p, Settings.Global.WINDOW_ANIMATION_SCALE, GlobalSettingsProto.WINDOW_ANIMATION_SCALE); dumpSetting(s, p, @@ -870,15 +964,6 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.GPU_DEBUG_LAYERS, GlobalSettingsProto.GPU_DEBUG_LAYERS); - dumpSetting(s, p, - Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, - GlobalSettingsProto.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING); - dumpSetting(s, p, - Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT, - GlobalSettingsProto.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT); - dumpSetting(s, p, - Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS, - GlobalSettingsProto.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS); // Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated. dumpSetting(s, p, Settings.Global.LOW_POWER_MODE, @@ -887,6 +972,9 @@ class SettingsProtoDumpUtil { Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, GlobalSettingsProto.LOW_POWER_MODE_TRIGGER_LEVEL); dumpSetting(s, p, + Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX, + GlobalSettingsProto.LOW_POWER_MODE_TRIGGER_LEVEL_MAX); + dumpSetting(s, p, Settings.Global.ALWAYS_FINISH_ACTIVITIES, GlobalSettingsProto.ALWAYS_FINISH_ACTIVITIES); dumpSetting(s, p, @@ -962,6 +1050,9 @@ class SettingsProtoDumpUtil { Settings.Global.POLICY_CONTROL, GlobalSettingsProto.POLICY_CONTROL); dumpSetting(s, p, + Settings.Global.EMULATE_DISPLAY_CUTOUT, + GlobalSettingsProto.EMULATE_DISPLAY_CUTOUT); + dumpSetting(s, p, Settings.Global.ZEN_MODE, GlobalSettingsProto.ZEN_MODE); dumpSetting(s, p, @@ -971,6 +1062,9 @@ class SettingsProtoDumpUtil { Settings.Global.ZEN_MODE_CONFIG_ETAG, GlobalSettingsProto.ZEN_MODE_CONFIG_ETAG); dumpSetting(s, p, + Settings.Global.ZEN_DURATION, + GlobalSettingsProto.ZEN_DURATION); + dumpSetting(s, p, Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, GlobalSettingsProto.HEADS_UP_NOTIFICATIONS_ENABLED); dumpSetting(s, p, @@ -1061,9 +1155,18 @@ class SettingsProtoDumpUtil { Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD, GlobalSettingsProto.STORAGE_SETTINGS_CLOBBER_THRESHOLD); dumpSetting(s, p, + Settings.Global.LOCATION_GLOBAL_KILL_SWITCH, + GlobalSettingsProto.LOCATION_GLOBAL_KILL_SWITCH); + dumpSetting(s, p, + Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION, + GlobalSettingsProto.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION); + dumpSetting(s, p, Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED, GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED); dumpSetting(s, p, + Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES, + GlobalSettingsProto.AUTOFILL_COMPAT_ALLOWED_PACKAGES); + dumpSetting(s, p, Global.HIDDEN_API_BLACKLIST_EXEMPTIONS, GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS); dumpSetting(s, p, @@ -1121,6 +1224,18 @@ class SettingsProtoDumpUtil { Settings.Global.NOTIFICATION_SNOOZE_OPTIONS, GlobalSettingsProto.NOTIFICATION_SNOOZE_OPTIONS); dumpSetting(s, p, + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, + GlobalSettingsProto.SQLITE_COMPATIBILITY_WAL_FLAGS); + dumpSetting(s, p, + Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, + GlobalSettingsProto.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING); + dumpSetting(s, p, + Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT, + GlobalSettingsProto.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT); + dumpSetting(s, p, + Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS, + GlobalSettingsProto.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS); + dumpSetting(s, p, Settings.Global.ZRAM_ENABLED, GlobalSettingsProto.ZRAM_ENABLED); dumpSetting(s, p, @@ -1138,14 +1253,19 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, GlobalSettingsProto.SHOW_ZEN_UPGRADE_NOTIFICATION); - dumpSetting(s, p, - Settings.Global.APP_AUTO_RESTRICTION_ENABLED, - GlobalSettingsProto.APP_AUTO_RESTRICTION_ENABLED); - dumpSetting(s, p, - Settings.Global.ZEN_DURATION, - GlobalSettingsProto.ZEN_DURATION); - // Please insert new settings using the same order as in Settings.Global. + + p.end(token); + } + + /** Dumps settings that use a common prefix into a repeated field. */ + private static void dumpRepeatedSetting(@NonNull SettingsState settings, + @NonNull ProtoOutputStream proto, String settingPrefix, long fieldId) { + for (String s : settings.getSettingNamesLocked()) { + if (s.startsWith(settingPrefix)) { + dumpSetting(settings, proto, s, fieldId); + } + } } /** Dump a single {@link SettingsState.Setting} to a proto buf */ @@ -1167,7 +1287,9 @@ class SettingsProtoDumpUtil { } static void dumpProtoSecureSettingsLocked( - @NonNull SettingsState s, @NonNull ProtoOutputStream p) { + @NonNull ProtoOutputStream p, long fieldId, @NonNull SettingsState s) { + final long token = p.start(fieldId); + s.dumpHistoricalOperations(p, SecureSettingsProto.HISTORICAL_OPERATIONS); // This uses the same order as in Settings.Secure. @@ -1199,6 +1321,24 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Secure.AUTOFILL_SERVICE, SecureSettingsProto.AUTOFILL_SERVICE); + dumpSetting(s, p, + Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, + SecureSettingsProto.AUTOFILL_FEATURE_FIELD_CLASSIFICATION); + dumpSetting(s, p, + Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE, + SecureSettingsProto.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE); + dumpSetting(s, p, + Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE, + SecureSettingsProto.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE); + dumpSetting(s, p, + Settings.Secure.AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT, + SecureSettingsProto.AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT); + dumpSetting(s, p, + Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH, + SecureSettingsProto.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH); + dumpSetting(s, p, + Settings.Secure.AUTOFILL_USER_DATA_MIN_VALUE_LENGTH, + SecureSettingsProto.AUTOFILL_USER_DATA_MIN_VALUE_LENGTH); // Settings.Secure.DEVICE_PROVISIONED intentionally excluded since it's deprecated. dumpSetting(s, p, Settings.Secure.USER_SETUP_COMPLETE, @@ -1209,9 +1349,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Secure.TV_USER_SETUP_COMPLETE, SecureSettingsProto.TV_USER_SETUP_COMPLETE); - dumpSetting(s, p, + dumpRepeatedSetting(s, p, Settings.Secure.COMPLETED_CATEGORY_PREFIX, - SecureSettingsProto.COMPLETED_CATEGORY_PREFIX); + SecureSettingsProto.COMPLETED_CATEGORIES); dumpSetting(s, p, Settings.Secure.ENABLED_INPUT_METHODS, SecureSettingsProto.ENABLED_INPUT_METHODS); @@ -1238,6 +1378,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Secure.LOCATION_MODE, SecureSettingsProto.LOCATION_MODE); + dumpSetting(s, p, + Settings.Secure.LOCATION_CHANGER, + SecureSettingsProto.LOCATION_CHANGER); // Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS intentionally excluded since it's deprecated. dumpSetting(s, p, Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, @@ -1309,6 +1452,9 @@ class SettingsProtoDumpUtil { Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, SecureSettingsProto.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES); dumpSetting(s, p, + Settings.Secure.KEYGUARD_SLICE_URI, + SecureSettingsProto.KEYGUARD_SLICE_URI); + dumpSetting(s, p, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, SecureSettingsProto.ACCESSIBILITY_SPEAK_PASSWORD); dumpSetting(s, p, @@ -1324,9 +1470,6 @@ class SettingsProtoDumpUtil { Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, SecureSettingsProto.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE); dumpSetting(s, p, - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE, - SecureSettingsProto.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE); - dumpSetting(s, p, Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SecureSettingsProto.ACCESSIBILITY_SOFT_KEYBOARD_MODE); dumpSetting(s, p, @@ -1618,6 +1761,12 @@ class SettingsProtoDumpUtil { Settings.Secure.ASSIST_DISCLOSURE_ENABLED, SecureSettingsProto.ASSIST_DISCLOSURE_ENABLED); dumpSetting(s, p, + Settings.Secure.SHOW_ROTATION_SUGGESTIONS, + SecureSettingsProto.SHOW_ROTATION_SUGGESTIONS); + dumpSetting(s, p, + Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, + SecureSettingsProto.NUM_ROTATION_SUGGESTIONS_ACCEPTED); + dumpSetting(s, p, Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT, SecureSettingsProto.ENABLED_NOTIFICATION_ASSISTANT); dumpSetting(s, p, @@ -1776,12 +1925,15 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING, SecureSettingsProto.BLUETOOTH_ON_WHILE_DRIVING); - // Please insert new settings using the same order as in Settings.Secure. + + p.end(token); } private static void dumpProtoSystemSettingsLocked( - @NonNull SettingsState s, @NonNull ProtoOutputStream p) { + @NonNull ProtoOutputStream p, long fieldId, @NonNull SettingsState s) { + final long token = p.start(fieldId); + s.dumpHistoricalOperations(p, SystemSettingsProto.HISTORICAL_OPERATIONS); // This uses the same order as in Settings.System. @@ -1794,11 +1946,11 @@ class SettingsProtoDumpUtil { Settings.System.ADVANCED_SETTINGS, SystemSettingsProto.ADVANCED_SETTINGS); // Settings.System.AIRPLANE_MODE_ON intentionally excluded since it's deprecated. - // Settings.System.RADIO_BLUETOOTH intentionally excluded since it's deprecated. - // Settings.System.RADIO_WIFI intentionally excluded since it's deprecated. - // Settings.System.RADIO_WIMAX intentionally excluded since it's deprecated. - // Settings.System.RADIO_CELL intentionally excluded since it's deprecated. - // Settings.System.RADIO_NFC intentionally excluded since it's deprecated. + // Settings.System.RADIO_BLUETOOTH intentionally excluded since it's just a constant. + // Settings.System.RADIO_WIFI intentionally excluded since it's just a constant. + // Settings.System.RADIO_WIMAX intentionally excluded since it's just a constant. + // Settings.System.RADIO_CELL intentionally excluded since it's just a constant. + // Settings.System.RADIO_NFC intentionally excluded since it's just a constant. // Settings.System.AIRPLANE_MODE_RADIOS intentionally excluded since it's deprecated. // Settings.System.AIRPLANE_MODE_TOGGLABLE_RADIOS intentionally excluded since it's deprecated. // Settings.System.WIFI_SLEEP_POLICY intentionally excluded since it's deprecated. @@ -1861,6 +2013,12 @@ class SettingsProtoDumpUtil { Settings.System.VIBRATE_INPUT_DEVICES, SystemSettingsProto.VIBRATE_INPUT_DEVICES); dumpSetting(s, p, + Settings.System.NOTIFICATION_VIBRATION_INTENSITY, + SystemSettingsProto.NOTIFICATION_VIBRATION_INTENSITY); + dumpSetting(s, p, + Settings.System.HAPTIC_FEEDBACK_INTENSITY, + SystemSettingsProto.HAPTIC_FEEDBACK_INTENSITY); + dumpSetting(s, p, Settings.System.VOLUME_RING, SystemSettingsProto.VOLUME_RING); dumpSetting(s, p, @@ -1973,6 +2131,9 @@ class SettingsProtoDumpUtil { Settings.System.TTY_MODE, SystemSettingsProto.TTY_MODE); dumpSetting(s, p, + Settings.System.RTT_CALLING_MODE, + SystemSettingsProto.RTT_CALLING_MODE); + dumpSetting(s, p, Settings.System.SOUND_EFFECTS_ENABLED, SystemSettingsProto.SOUND_EFFECTS_ENABLED); dumpSetting(s, p, @@ -2038,5 +2199,7 @@ class SettingsProtoDumpUtil { // they're deprecated from Settings.System. // Please insert new settings using the same order as in Settings.System. + + p.end(token); } } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 937b9397a9a5..589ae2a1193f 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -118,6 +118,7 @@ <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" /> <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" /> <uses-permission android:name="android.permission.GET_APP_OPS_STATS" /> + <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" /> <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING" /> diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java index 6131acc91ca5..aa2fb32f13a8 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java @@ -16,6 +16,7 @@ package com.android.systemui.plugins.statusbar.phone; import android.graphics.Canvas; import android.view.MotionEvent; +import android.view.View; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.annotations.ProvidesInterface; @@ -42,6 +43,8 @@ public interface NavGesture extends Plugin { public void onLayout(boolean changed, int left, int top, int right, int bottom); + public void onNavigationButtonLongPress(View v); + public default void destroy() { } } diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 12fccd4c4fdf..4d6509de9c5d 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -401,9 +401,9 @@ <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Aucune\ninterruption"</string> <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorité\nuniquement"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string> - <string name="keyguard_indication_charging_time" msgid="2056340799276374421">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Rechargement… (rechargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> - <string name="keyguard_indication_charging_time_fast" msgid="7767562163577492332">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Rechargement rapide… (à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> - <string name="keyguard_indication_charging_time_slowly" msgid="3769655133567307069">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Rechargement lent… (à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time" msgid="2056340799276374421">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Rechargement… (rechargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="7767562163577492332">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Rechargement rapide… (à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="3769655133567307069">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Rechargement lent… (à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index cce38f16143a..2c73f1e97b09 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -377,6 +377,9 @@ <!-- Content description of the data connection type 3.5G. [CHAR LIMIT=NONE] --> <string name="data_connection_3_5g">3.5G</string> + <!-- Content description of the data connection type 3.5G+. [CHAR LIMIT=NONE] --> + <string name="data_connection_3_5g_plus">3.5G+</string> + <!-- Content description of the data connection type 4G . [CHAR LIMIT=NONE] --> <string name="data_connection_4g">4G</string> @@ -1059,6 +1062,9 @@ <!-- The text to clear all notifications. [CHAR LIMIT=60] --> <string name="clear_all_notifications_text">Clear all</string> + <!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] --> + <string name="dnd_suppressing_shade_text">Do Not disturb is hiding notifications</string> + <!-- Media projection permission dialog action text. [CHAR LIMIT=60] --> <string name="media_projection_action_text">Start now</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl index ef36610b48c6..861244539725 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl @@ -80,4 +80,17 @@ oneway interface IOverviewProxy { * Sent when overview is to be hidden. */ void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey); + + /** + * Sent when a user swipes up over the navigation bar to launch overview. Swipe up is determined + * by passing the touch slop in the direction towards launcher from navigation bar. During and + * after this event is sent the caller will continue to send motion events. The motion + * {@param event} passed after the touch slop was exceeded will also be passed after by + * {@link onMotionEvent}. Since motion events will be sent, motion up or cancel can still be + * sent to cancel overview regardless the current state of launcher (eg. if overview is already + * visible, this event will still be sent if user swipes up). When this signal is sent, + * navigation bar will not handle any gestures such as quick scrub or switch and the home button + * will cancel (long) press. + */ + void onQuickStep(in MotionEvent event); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 846aaddf74de..4799f398fb7a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -36,11 +36,6 @@ interface ISystemUiProxy { void startScreenPinning(int taskId) = 1; /** - * Called when the overview service has started the recents animation. - */ - void onRecentsAnimationStarted() = 2; - - /** * Specifies the text to be shown for onboarding the new swipe-up gesture to access recents. */ void setRecentsOnboardingText(CharSequence text) = 3; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index 9a7abf82c56c..940c9ef522a3 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -51,6 +51,14 @@ public class RecentsAnimationControllerCompat { } } + public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) { + try { + mAnimationController.setAnimationTargetsBehindSystemBars(behindSystemBars); + } catch (RemoteException e) { + Log.e(TAG, "Failed to set whether animation targets are behind system bars", e); + } + } + public void finish(boolean toHome) { try { mAnimationController.finish(toHome); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java index 5fff5febec85..098698aa1c5c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java @@ -29,6 +29,11 @@ public class RemoteAnimationDefinitionCompat { mWrapped.addRemoteAnimation(transition, adapter.getWrapped()); } + public void addRemoteAnimation(int transition, int activityTypeFilter, + RemoteAnimationAdapterCompat adapter) { + mWrapped.addRemoteAnimation(transition, activityTypeFilter, adapter.getWrapped()); + } + RemoteAnimationDefinition getWrapped() { return mWrapped; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index a9c80c62e998..2de3ae2bd9e4 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -18,6 +18,7 @@ package com.android.systemui.shared.system; import static android.view.Display.DEFAULT_DISPLAY; +import android.app.WindowConfiguration; import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; @@ -58,6 +59,8 @@ public class WindowManagerWrapper { public static final int TRANSIT_KEYGUARD_OCCLUDE = WindowManager.TRANSIT_KEYGUARD_OCCLUDE; public static final int TRANSIT_KEYGUARD_UNOCCLUDE = WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; + public static final int ACTIVITY_TYPE_STANDARD = WindowConfiguration.ACTIVITY_TYPE_STANDARD; + private static final WindowManagerWrapper sInstance = new WindowManagerWrapper(); public static WindowManagerWrapper getInstance() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index f0952f9641f2..10ba7f6704de 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -47,12 +47,12 @@ import java.util.HashMap; import java.util.List; import java.util.function.Consumer; -import androidx.app.slice.Slice; -import androidx.app.slice.SliceItem; -import androidx.app.slice.core.SliceQuery; -import androidx.app.slice.widget.ListContent; -import androidx.app.slice.widget.RowContent; -import androidx.app.slice.widget.SliceLiveData; +import androidx.slice.Slice; +import androidx.slice.SliceItem; +import androidx.slice.core.SliceQuery; +import androidx.slice.widget.ListContent; +import androidx.slice.widget.RowContent; +import androidx.slice.widget.SliceLiveData; /** * View visible under the clock on the lock screen and AoD. @@ -117,7 +117,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe private void showSlice(Slice slice) { - ListContent lc = new ListContent(slice); + ListContent lc = new ListContent(getContext(), slice); mHasHeader = lc.hasHeader(); List<SliceItem> subItems = lc.getRowItems(); if (!mHasHeader) { @@ -125,7 +125,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe } else { mTitle.setVisibility(VISIBLE); // If there's a header it'll be the first subitem - RowContent header = new RowContent(subItems.get(0), true /* showStartItem */); + RowContent header = new RowContent(getContext(), subItems.get(0), + true /* showStartItem */); SliceItem mainTitle = header.getTitleItem(); CharSequence title = mainTitle != null ? mainTitle.getText() : null; mTitle.setText(title); @@ -149,7 +150,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it for (int i = startIndex; i < subItemsCount; i++) { SliceItem item = subItems.get(i); - RowContent rc = new RowContent(item, true /* showStartItem */); + RowContent rc = new RowContent(getContext(), item, true /* showStartItem */); final Uri itemTag = item.getSlice().getUri(); // Try to reuse the view if already exists in the layout KeyguardSliceButton button = mRow.findViewWithTag(itemTag); @@ -182,6 +183,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe } button.setCompoundDrawables(iconDrawable, null, null, null); button.setOnClickListener(this); + button.setClickable(pendingIntent != null); } // Removing old views diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index cad155c43867..5fce0a6d641c 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -45,6 +45,7 @@ import com.android.systemui.power.EnhancedEstimatesImpl; import com.android.systemui.power.PowerNotificationWarnings; import com.android.systemui.power.PowerUI; import com.android.systemui.statusbar.AppOpsListener; +import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.phone.ConfigurationControllerImpl; import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl; import com.android.systemui.statusbar.phone.LightBarController; @@ -317,6 +318,8 @@ public class Dependency extends SystemUI { mProviders.put(AppOpsListener.class, () -> new AppOpsListener(mContext)); + mProviders.put(VibratorHelper.class, () -> new VibratorHelper(mContext)); + // Put all dependencies above here so the factory can override them if it wants. SystemUIFactory.getInstance().injectDependencies(mProviders, mContext); } diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java index 041af0e47119..a4af6b26a854 100644 --- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java @@ -102,15 +102,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } - public void onRecentsAnimationStarted() { - long token = Binder.clearCallingIdentity(); - try { - mHandler.post(OverviewProxyService.this::notifyRecentsAnimationStarted); - } finally { - Binder.restoreCallingIdentity(token); - } - } - public void onSplitScreenInvoked() { long token = Binder.clearCallingIdentity(); try { @@ -283,9 +274,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } - private void notifyRecentsAnimationStarted() { + public void notifyQuickStepStarted() { for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { - mConnectionCallbacks.get(i).onRecentsAnimationStarted(); + mConnectionCallbacks.get(i).onQuickStepStarted(); } } @@ -300,7 +291,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis public interface OverviewProxyListener { default void onConnectionChanged(boolean isConnected) {} - default void onRecentsAnimationStarted() {} + default void onQuickStepStarted() {} default void onInteractionFlagsChanged(@InteractionType int flags) {} } } diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index ec2390fbcfc6..9a20c81c4919 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -33,6 +33,7 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManager; +import android.os.SystemProperties; import android.provider.Settings.Secure; import android.support.annotation.VisibleForTesting; import android.util.DisplayMetrics; @@ -65,6 +66,8 @@ import com.android.systemui.tuner.TunerService.Tunable; public class ScreenDecorations extends SystemUI implements Tunable { public static final String SIZE = "sysui_rounded_size"; public static final String PADDING = "sysui_rounded_content_padding"; + private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS = + SystemProperties.getBoolean("debug.screenshot_rounded_corners", false); private int mRoundedDefault; private View mOverlay; @@ -237,7 +240,12 @@ public class ScreenDecorations extends SystemUI implements Tunable { | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT); lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS - | WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; + | WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; + + if (!DEBUG_SCREENSHOT_ROUNDED_CORNERS) { + lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; + } + lp.setTitle("ScreenDecorOverlay"); lp.gravity = Gravity.TOP | Gravity.LEFT; lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; @@ -380,6 +388,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { mBounds.set(mInfo.displayCutout.getBounds()); localBounds(mBoundingRect); mInfo.displayCutout.getBounds().getBoundaryPath(mBoundingPath); + invalidate(); newVisible = VISIBLE; } else { newVisible = GONE; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index 26618bff4db7..d81b32b162b7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -40,10 +40,10 @@ import java.util.Date; import java.util.Locale; import java.util.concurrent.TimeUnit; -import androidx.app.slice.Slice; -import androidx.app.slice.SliceProvider; -import androidx.app.slice.builders.ListBuilder; -import androidx.app.slice.builders.ListBuilder.RowBuilder; +import androidx.slice.Slice; +import androidx.slice.SliceProvider; +import androidx.slice.builders.ListBuilder; +import androidx.slice.builders.ListBuilder.RowBuilder; /** * Simple Slice provider that shows the current date. diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index 0486a9dcca74..a4927b7704c5 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -63,7 +63,6 @@ import android.util.Pair; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.View.OnTouchListener; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.WindowManager.LayoutParams; @@ -551,7 +550,6 @@ public class PipMenuActivity extends Activity { alpha = (int) (interpolatedAlpha * 255); } else { if (mMenuState == MENU_STATE_CLOSE) { - mSettingsButton.setAlpha(menuAlpha); mDismissButton.setAlpha(menuAlpha); } alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java index d9359a43d8a8..c348187115f0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java @@ -189,7 +189,7 @@ public class RecentsOnboarding { } } - public void onRecentsAnimationStarted() { + public void onQuickStepStarted() { boolean alreadySeenRecentsOnboarding = Prefs.getBoolean(mContext, Prefs.Key.HAS_SEEN_RECENTS_ONBOARDING, false); if (!alreadySeenRecentsOnboarding) { diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java index 406eef82f737..f2a7adf680f8 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java @@ -368,7 +368,9 @@ public class BrightnessController implements ToggleSlider.Listener { } else { final int val = value + mMinimumBacklight; if (stopTracking) { - MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS, val); + final int metric = mAutomatic ? + MetricsEvent.ACTION_BRIGHTNESS_AUTO : MetricsEvent.ACTION_BRIGHTNESS; + MetricsLogger.action(mContext, metric, val); } setBrightness(val); if (!tracking) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java index 58adde269758..3698c3a0038d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar; import android.annotation.ColorInt; +import android.annotation.StringRes; import android.content.Context; import android.content.res.Configuration; import android.util.AttributeSet; @@ -30,6 +31,7 @@ import com.android.systemui.statusbar.stack.StackScrollState; public class EmptyShadeView extends StackScrollerDecorView { private TextView mEmptyText; + private @StringRes int mText = R.string.empty_shade_text; public EmptyShadeView(Context context, AttributeSet attrs) { super(context, attrs); @@ -38,7 +40,7 @@ public class EmptyShadeView extends StackScrollerDecorView { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - mEmptyText.setText(R.string.empty_shade_text); + mEmptyText.setText(mText); } @Override @@ -50,6 +52,11 @@ public class EmptyShadeView extends StackScrollerDecorView { mEmptyText.setTextColor(color); } + public void setText(@StringRes int text) { + mText = text; + mEmptyText.setText(mText); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 110995505444..010b1651a0d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -157,7 +157,7 @@ public class KeyguardBouncer { public void onFullyHidden() { if (!mShowingSoon) { cancelShowRunnable(); - inflateView(); + mRoot.setVisibility(View.INVISIBLE); mFalsingManager.onBouncerHidden(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 9fa06f77fe9e..c5781d9a46c1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -175,8 +175,8 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } @Override - public void onRecentsAnimationStarted() { - mNavigationBarView.setRecentsAnimationStarted(true); + public void onQuickStepStarted() { + mNavigationBarView.onQuickStepStarted(); // Use navbar dragging as a signal to hide the rotate button setRotateSuggestionButtonState(false); @@ -343,10 +343,19 @@ public class NavigationBarFragment extends Fragment implements Callbacks { boolean showImeSwitcher) { boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0; int hints = mNavigationIconHints; - if (imeShown && backDisposition != InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS) { - hints |= NAVIGATION_HINT_BACK_ALT; - } else { - hints &= ~NAVIGATION_HINT_BACK_ALT; + switch (backDisposition) { + case InputMethodService.BACK_DISPOSITION_DEFAULT: + case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS: + case InputMethodService.BACK_DISPOSITION_WILL_DISMISS: + if (imeShown) { + hints |= NAVIGATION_HINT_BACK_ALT; + } else { + hints &= ~NAVIGATION_HINT_BACK_ALT; + } + break; + case InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING: + hints &= ~NAVIGATION_HINT_BACK_ALT; + break; } if (showImeSwitcher) { hints |= NAVIGATION_HINT_IME_SHOWN; @@ -751,6 +760,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { if (shouldDisableNavbarGestures()) { return false; } + mNavigationBarView.onNavigationButtonLongPress(v); mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS); mAssistManager.startAssist(new Bundle() /* args */); mStatusBar.awakenDreams(); @@ -787,10 +797,12 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } private boolean onLongPressBackHome(View v) { + mNavigationBarView.onNavigationButtonLongPress(v); return onLongPressNavigationButtons(v, R.id.back, R.id.home); } private boolean onLongPressBackRecents(View v) { + mNavigationBarView.onNavigationButtonLongPress(v); return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java index 6a1ed51e85b4..cd000fe4ba70 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -19,31 +19,22 @@ package com.android.systemui.statusbar.phone; import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.DOCKED_LEFT; import static android.view.WindowManager.DOCKED_TOP; -import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY; -import static com.android.systemui.OverviewProxyService.TAG_OPS; import android.app.ActivityManager; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; -import android.graphics.Matrix; import android.graphics.Rect; -import android.os.RemoteException; -import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.systemui.Dependency; -import com.android.systemui.OverviewProxyService; -import com.android.systemui.OverviewProxyService.OverviewProxyListener; import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper; -import com.android.systemui.shared.recents.IOverviewProxy; -import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.stackdivider.Divider; import com.android.systemui.tuner.TunerService; @@ -75,25 +66,14 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture private NavigationBarView mNavigationBarView; private boolean mIsVertical; - private final QuickScrubController mQuickScrubController; + private final QuickStepController mQuickStepController; private final int mScrollTouchSlop; - private final Matrix mTransformGlobalMatrix = new Matrix(); - private final Matrix mTransformLocalMatrix = new Matrix(); private final StatusBar mStatusBar; private int mTouchDownX; private int mTouchDownY; private boolean mDownOnRecents; private VelocityTracker mVelocityTracker; - private OverviewProxyService mOverviewProxyService = Dependency.get(OverviewProxyService.class); - private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() { - @Override - public void onRecentsAnimationStarted() { - mRecentsAnimationStarted = true; - mQuickScrubController.setRecentsAnimationStarted(true /* started */); - } - }; - private boolean mRecentsAnimationStarted; private boolean mDockWindowEnabled; private boolean mDockWindowTouchSlopExceeded; private int mDragMode; @@ -103,14 +83,12 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class); Resources r = context.getResources(); mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance); - mQuickScrubController = new QuickScrubController(context); + mQuickStepController = new QuickStepController(context); Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE); - mOverviewProxyService.addCallback(mOverviewProxyListener); } public void destroy() { Dependency.get(TunerService.class).removeTunable(this); - mOverviewProxyService.removeCallback(mOverviewProxyListener); } public void setComponents(RecentsComponent recentsComponent, Divider divider, @@ -118,65 +96,19 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture mRecentsComponent = recentsComponent; mDivider = divider; mNavigationBarView = navigationBarView; - mQuickScrubController.setComponents(mNavigationBarView); + mQuickStepController.setComponents(mNavigationBarView); } public void setBarState(boolean isVertical, boolean isRTL) { mIsVertical = isVertical; - mQuickScrubController.setBarState(isVertical, isRTL); - } - - private boolean proxyMotionEvents(MotionEvent event) { - final IOverviewProxy overviewProxy = mOverviewProxyService.getProxy(); - if (overviewProxy != null && mNavigationBarView.isQuickStepSwipeUpEnabled()) { - mNavigationBarView.requestUnbufferedDispatch(event); - event.transform(mTransformGlobalMatrix); - try { - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget()); - } - overviewProxy.onMotionEvent(event); - if (DEBUG_OVERVIEW_PROXY) { - Log.d(TAG_OPS, "Send MotionEvent: " + event.toString()); - } - return true; - } catch (RemoteException e) { - Log.e(TAG, "Callback failed", e); - } finally { - event.transform(mTransformLocalMatrix); - } - } - return false; + mQuickStepController.setBarState(isVertical, isRTL); } public boolean onInterceptTouchEvent(MotionEvent event) { - if (mNavigationBarView.inScreenPinning() || mStatusBar.isKeyguardShowing() - || !mStatusBar.isPresenterFullyCollapsed()) { + if (!canHandleGestures()) { return false; } - - int action = event.getActionMasked(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - mTouchDownX = (int) event.getX(); - mTouchDownY = (int) event.getY(); - mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX); - mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX); - mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix); - mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix); - mRecentsAnimationStarted = false; - mQuickScrubController.setRecentsAnimationStarted(false /* started */); - break; - } - } - boolean handledByQuickscrub = mQuickScrubController.onInterceptTouchEvent(event); - if (!handledByQuickscrub) { - // Proxy motion events until we start intercepting for quickscrub - proxyMotionEvents(event); - } - - boolean result = handledByQuickscrub; - result |= mRecentsAnimationStarted; + boolean result = mQuickStepController.onInterceptTouchEvent(event); if (mDockWindowEnabled) { result |= interceptDockWindowEvent(event); } @@ -184,18 +116,10 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture } public boolean onTouchEvent(MotionEvent event) { - if (mNavigationBarView.inScreenPinning() || mStatusBar.isKeyguardShowing() - || !mStatusBar.isPresenterFullyCollapsed()) { + if (!canHandleGestures()) { return false; } - - // The same down event was just sent on intercept and therefore can be ignored here - boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN - && mOverviewProxyService.getProxy() != null; - boolean result = mQuickScrubController.onTouchEvent(event) - || ignoreProxyDownEvent - || proxyMotionEvents(event); - result |= mRecentsAnimationStarted; + boolean result = mQuickStepController.onTouchEvent(event); if (mDockWindowEnabled) { result |= handleDockWindowEvent(event); } @@ -203,17 +127,19 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture } public void onDraw(Canvas canvas) { - if (mNavigationBarView.isQuickScrubEnabled()) { - mQuickScrubController.onDraw(canvas); - } + mQuickStepController.onDraw(canvas); } public void onLayout(boolean changed, int left, int top, int right, int bottom) { - mQuickScrubController.onLayout(changed, left, top, right, bottom); + mQuickStepController.onLayout(changed, left, top, right, bottom); } public void onDarkIntensityChange(float intensity) { - mQuickScrubController.onDarkIntensityChange(intensity); + mQuickStepController.onDarkIntensityChange(intensity); + } + + public void onNavigationButtonLongPress(View v) { + mQuickStepController.onNavigationButtonLongPress(v); } private boolean interceptDockWindowEvent(MotionEvent event) { @@ -342,6 +268,11 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture mVelocityTracker = null; } + private boolean canHandleGestures() { + return !mNavigationBarView.inScreenPinning() && !mStatusBar.isKeyguardShowing() + && mStatusBar.isPresenterFullyCollapsed(); + } + private int calculateDragMode() { if (mIsVertical && !mDivider.getView().isHorizontalDivision()) { return DRAG_MODE_DIVIDER; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 03efbb29e88a..fcbd37c50f73 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -247,7 +247,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav mOverviewProxyService = Dependency.get(OverviewProxyService.class); mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService); - mVibratorHelper = new VibratorHelper(context); + mVibratorHelper = Dependency.get(VibratorHelper.class); mConfiguration = new Configuration(); mConfiguration.updateFrom(context.getResources().getConfiguration()); @@ -290,18 +290,12 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav notifyVerticalChangedListener(mVertical); } - public void setRecentsAnimationStarted(boolean started) { + public void onQuickStepStarted() { if (mRecentsOnboarding != null) { - mRecentsOnboarding.onRecentsAnimationStarted(); + mRecentsOnboarding.onQuickStepStarted(); } } - public void onConnectionChanged(boolean isConnected) { - updateSlippery(); - updateNavButtonIcons(); - setUpSwipeUpOnboarding(isConnected); - } - @Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getActionMasked()) { @@ -675,6 +669,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav } } + public void onNavigationButtonLongPress(View v) { + mGestureHelper.onNavigationButtonLongPress(v); + } + public void onPanelExpandedChange(boolean expanded) { updateSlippery(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 3de0a41dc67d..7f1e9d0e1972 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -38,6 +38,7 @@ import android.widget.FrameLayout; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.LatencyTracker; import com.android.systemui.DejankUtils; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.classifier.FalsingManager; @@ -207,7 +208,7 @@ public abstract class PanelView extends FrameLayout { mFalsingManager = FalsingManager.getInstance(context); mNotificationsDragEnabled = getResources().getBoolean(R.bool.config_enableNotificationShadeDrag); - mVibratorHelper = new VibratorHelper(context); + mVibratorHelper = Dependency.get(VibratorHelper.class); mVibrateOnOpening = mContext.getResources().getBoolean( R.bool.config_vibrateOnIconAnimation); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java index 00aff53595ff..19544b170d1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java @@ -25,6 +25,7 @@ import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.os.Handler; @@ -55,10 +56,10 @@ import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ /** * Class to detect gestures on the navigation bar and implement quick scrub and switch. */ -public class QuickScrubController extends GestureDetector.SimpleOnGestureListener implements +public class QuickStepController extends GestureDetector.SimpleOnGestureListener implements GestureHelper { - private static final String TAG = "QuickScrubController"; + private static final String TAG = "QuickStepController"; private static final int QUICK_SWITCH_FLING_VELOCITY = 0; private static final int ANIM_DURATION_MS = 200; private static final long LONG_PRESS_DELAY_MS = 225; @@ -75,7 +76,8 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene private boolean mDraggingActive; private boolean mQuickScrubActive; private boolean mAllowQuickSwitch; - private boolean mRecentsAnimationStarted; + private boolean mAllowGestureDetection; + private boolean mQuickStepStarted; private float mDownOffset; private float mTranslation; private int mTouchDownX; @@ -101,6 +103,8 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene private final ValueAnimator mButtonAnimator; private final AnimatorSet mQuickScrubEndAnimator; private final Context mContext; + private final Matrix mTransformGlobalMatrix = new Matrix(); + private final Matrix mTransformLocalMatrix = new Matrix(); private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator(); private final AnimatorUpdateListener mTrackAnimatorListener = valueAnimator -> { @@ -123,7 +127,6 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene private AnimatorListenerAdapter mQuickScrubEndListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mNavigationBarView.getHomeButton().setClickable(true); mQuickScrubActive = false; mTranslation = 0; mQuickScrubEndAnimator.setCurrentPlayTime(mQuickScrubEndAnimator.getDuration()); @@ -165,7 +168,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene } }; - public QuickScrubController(Context context) { + public QuickStepController(Context context) { mContext = context; mScrollTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mOverviewEventSender = Dependency.get(OverviewProxyService.class); @@ -197,31 +200,35 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { - final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton(); - if (!mNavigationBarView.isQuickScrubEnabled()) { - homeButton.setDelayTouchFeedback(false); - return false; - } - return handleTouchEvent(event); } /** - * @return true if we want to handle touch events for quick scrub/switch and prevent proxying - * the event to the overview service. + * @return true if we want to handle touch events for quick scrub/switch or if down event (that + * will get consumed and ignored). No events will be proxied to the overview service. */ @Override public boolean onTouchEvent(MotionEvent event) { - return handleTouchEvent(event); + // The same down event was just sent on intercept and therefore can be ignored here + final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN + && mOverviewEventSender.getProxy() != null; + return ignoreProxyDownEvent || handleTouchEvent(event); } private boolean handleTouchEvent(MotionEvent event) { - final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy(); + if (!mNavigationBarView.isQuickScrubEnabled() + && !mNavigationBarView.isQuickStepSwipeUpEnabled()) { + mNavigationBarView.getHomeButton().setDelayTouchFeedback(false /* delay */); + return false; + } + mNavigationBarView.requestUnbufferedDispatch(event); + final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton(); if (mGestureDetector.onTouchEvent(event)) { // If the fling has been handled on UP, then skip proxying the UP return true; } + final boolean homePressed = mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME; int action = event.getAction(); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { @@ -232,89 +239,99 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene mQuickScrubEndAnimator.end(); } mHomeButtonView = homeButton.getCurrentView(); - if (mNavigationBarView.isQuickScrubEnabled() - && mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME) { - mTouchDownX = x; - mTouchDownY = y; - homeButton.setDelayTouchFeedback(true); + homeButton.setDelayTouchFeedback(true /* delay */); + mTouchDownX = x; + mTouchDownY = y; + if (homePressed) { mHandler.postDelayed(mLongPressRunnable, LONG_PRESS_DELAY_MS); - } else { - homeButton.setDelayTouchFeedback(false); - mTouchDownX = mTouchDownY = -1; } + mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX); + mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX); + mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix); + mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix); + mQuickStepStarted = false; mAllowQuickSwitch = true; + mAllowGestureDetection = true; break; } case MotionEvent.ACTION_MOVE: { - if (mTouchDownX != -1) { - int x = (int) event.getX(); - int y = (int) event.getY(); - int xDiff = Math.abs(x - mTouchDownX); - int yDiff = Math.abs(y - mTouchDownY); - boolean exceededTouchSlopX = xDiff > mScrollTouchSlop && xDiff > yDiff; - boolean exceededTouchSlopY = yDiff > mScrollTouchSlop && yDiff > xDiff; - boolean exceededTouchSlop, exceededPerpendicularTouchSlop; - int pos, touchDown, offset, trackSize; - - if (mIsVertical) { - exceededTouchSlop = exceededTouchSlopY; - exceededPerpendicularTouchSlop = exceededTouchSlopX; - pos = y; - touchDown = mTouchDownY; - offset = pos - mTrackRect.top; - trackSize = mTrackRect.height(); - } else { - exceededTouchSlop = exceededTouchSlopX; - exceededPerpendicularTouchSlop = exceededTouchSlopY; - pos = x; - touchDown = mTouchDownX; - offset = pos - mTrackRect.left; - trackSize = mTrackRect.width(); - } - // Do not start scrubbing when dragging in the perpendicular direction if we - // haven't already started quickscrub - if (!mDraggingActive && !mQuickScrubActive && exceededPerpendicularTouchSlop) { - mHandler.removeCallbacksAndMessages(null); - return false; - } - if (!mDragPositive) { - offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width(); + if (mQuickStepStarted || !mAllowGestureDetection){ + break; + } + int x = (int) event.getX(); + int y = (int) event.getY(); + int xDiff = Math.abs(x - mTouchDownX); + int yDiff = Math.abs(y - mTouchDownY); + boolean exceededTouchSlopX = xDiff > mScrollTouchSlop && xDiff > yDiff; + boolean exceededTouchSlopY = yDiff > mScrollTouchSlop && yDiff > xDiff; + boolean exceededTouchSlop, exceededPerpendicularTouchSlop; + int pos, touchDown, offset, trackSize; + + if (mIsVertical) { + exceededTouchSlop = exceededTouchSlopY; + exceededPerpendicularTouchSlop = exceededTouchSlopX; + pos = y; + touchDown = mTouchDownY; + offset = pos - mTrackRect.top; + trackSize = mTrackRect.height(); + } else { + exceededTouchSlop = exceededTouchSlopX; + exceededPerpendicularTouchSlop = exceededTouchSlopY; + pos = x; + touchDown = mTouchDownX; + offset = pos - mTrackRect.left; + trackSize = mTrackRect.width(); + } + // Decide to start quickstep if dragging away from the navigation bar, otherwise in + // the parallel direction, decide to start quickscrub. Only one may run. + if (!mDraggingActive && !mQuickScrubActive && exceededPerpendicularTouchSlop) { + if (mNavigationBarView.isQuickStepSwipeUpEnabled()) { + startQuickStep(event); } + break; + } - // Control the button movement - if (!mDraggingActive && exceededTouchSlop && !mRecentsAnimationStarted) { - boolean allowDrag = !mDragPositive - ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown; - if (allowDrag) { - mDownOffset = offset; - homeButton.setClickable(false); - mDraggingActive = true; - } + // Do not handle quick scrub/switch if disabled or hit target is not home button + if (!homePressed || !mNavigationBarView.isQuickScrubEnabled()) { + break; + } + + if (!mDragPositive) { + offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width(); + } + + // Control the button movement + if (!mDraggingActive && exceededTouchSlop) { + boolean allowDrag = !mDragPositive + ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown; + if (allowDrag) { + mDownOffset = offset; + homeButton.abortCurrentGesture(); + mDraggingActive = true; } - if (mDraggingActive && (mDragPositive && offset >= 0 - || !mDragPositive && offset <= 0)) { - float scrubFraction = - Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1); - mTranslation = !mDragPositive - ? Utilities.clamp(offset - mDownOffset, -trackSize, 0) - : Utilities.clamp(offset - mDownOffset, 0, trackSize); - if (mQuickScrubActive) { - try { - mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction); - if (DEBUG_OVERVIEW_PROXY) { - Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction); - } - } catch (RemoteException e) { - Log.e(TAG, "Failed to send progress of quick scrub.", e); + } + if (mDraggingActive && (mDragPositive && offset >= 0 + || !mDragPositive && offset <= 0)) { + float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1); + mTranslation = !mDragPositive + ? Utilities.clamp(offset - mDownOffset, -trackSize, 0) + : Utilities.clamp(offset - mDownOffset, 0, trackSize); + if (mQuickScrubActive) { + try { + mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction); + if (DEBUG_OVERVIEW_PROXY) { + Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction); } - } else { - mTranslation /= SWITCH_STICKINESS; - } - if (mIsVertical) { - mHomeButtonView.setTranslationY(mTranslation); - } else { - mHomeButtonView.setTranslationX(mTranslation); + } catch (RemoteException e) { + Log.e(TAG, "Failed to send progress of quick scrub.", e); } + } else { + mTranslation /= SWITCH_STICKINESS; + } + if (mIsVertical) { + mHomeButtonView.setTranslationY(mTranslation); + } else { + mHomeButtonView.setTranslationX(mTranslation); } } break; @@ -324,11 +341,20 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene endQuickScrub(true /* animate */); break; } - return mDraggingActive || mQuickScrubActive; + + // Proxy motion events to launcher if not handled by quick scrub/switch + boolean handled = mDraggingActive || mQuickScrubActive; + if (!handled && mAllowGestureDetection) { + proxyMotionEvents(event); + } + return handled || mQuickStepStarted; } @Override public void onDraw(Canvas canvas) { + if (mNavigationBarView.isQuickScrubEnabled()) { + return; + } int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor, mDarkTrackColor); mTrackPaint.setColor(color); @@ -381,6 +407,31 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene } } + @Override + public void onNavigationButtonLongPress(View v) { + mAllowGestureDetection = false; + mHandler.removeCallbacksAndMessages(null); + } + + private void startQuickStep(MotionEvent event) { + mQuickStepStarted = true; + event.transform(mTransformGlobalMatrix); + try { + mOverviewEventSender.getProxy().onQuickStep(event); + if (DEBUG_OVERVIEW_PROXY) { + Log.d(TAG_OPS, "Quick Step Start"); + } + } catch (RemoteException e) { + Log.e(TAG, "Failed to send quick step started.", e); + } finally { + event.transform(mTransformLocalMatrix); + } + mOverviewEventSender.notifyQuickStepStarted(); + mNavigationBarView.getHomeButton().abortCurrentGesture(); + cancelQuickSwitch(); + mHandler.removeCallbacksAndMessages(null); + } + private void startQuickScrub() { if (!mQuickScrubActive && mDraggingActive) { mQuickScrubActive = true; @@ -396,9 +447,6 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene } catch (RemoteException e) { Log.e(TAG, "Failed to send start of quick scrub.", e); } - } else { - // After long press do not allow quick scrub/switch - mTouchDownX = -1; } } @@ -421,11 +469,24 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene mDraggingActive = false; } - public void setRecentsAnimationStarted(boolean started) { - mRecentsAnimationStarted = started; - if (started) { - cancelQuickSwitch(); + private boolean proxyMotionEvents(MotionEvent event) { + final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy(); + event.transform(mTransformGlobalMatrix); + try { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget()); + } + overviewProxy.onMotionEvent(event); + if (DEBUG_OVERVIEW_PROXY) { + Log.d(TAG_OPS, "Send MotionEvent: " + event.toString()); + } + return true; + } catch (RemoteException e) { + Log.e(TAG, "Callback failed", e); + } finally { + event.transform(mTransformLocalMatrix); } + return false; } public void cancelQuickSwitch() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 5c7752401b83..2e45b120a75f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -232,6 +232,7 @@ import com.android.systemui.statusbar.policy.PreviewInflater; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.util.NotificationChannels; import com.android.systemui.volume.VolumeComponent; @@ -407,6 +408,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected NotificationEntryManager mEntryManager; protected NotificationViewHierarchyManager mViewHierarchyManager; protected AppOpsListener mAppOpsListener; + private ZenModeController mZenController; /** * Helper that is responsible for showing the right toast when a disallowed activity operation @@ -626,6 +628,7 @@ public class StatusBar extends SystemUI implements DemoMode, mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class); mAppOpsListener = Dependency.get(AppOpsListener.class); mAppOpsListener.setUpWithPresenter(this, mEntryManager); + mZenController = Dependency.get(ZenModeController.class); mColorExtractor = Dependency.get(SysuiColorExtractor.class); mColorExtractor.addOnColorsChangedListener(this); @@ -1166,6 +1169,7 @@ public class StatusBar extends SystemUI implements DemoMode, } mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate( R.layout.status_bar_no_notifications, mStackScroller, false); + mEmptyShadeView.setText(R.string.empty_shade_text); mStackScroller.setEmptyShadeView(mEmptyShadeView); } @@ -1498,6 +1502,9 @@ public class StatusBar extends SystemUI implements DemoMode, return entry.row.getParent() instanceof NotificationStackScrollLayout; } + public boolean areNotificationsHidden() { + return mZenController.areNotificationsHiddenInShade(); + } public void requestNotificationUpdate() { mEntryManager.updateNotifications(); @@ -4624,8 +4631,9 @@ public class StatusBar extends SystemUI implements DemoMode, != FingerprintUnlockController.MODE_UNLOCK); if (mBouncerShowing) { - mScrimController.transitionTo( - mIsOccluded ? ScrimState.BOUNCER_OCCLUDED : ScrimState.BOUNCER); + final boolean qsExpanded = mQSPanel != null && mQSPanel.isExpanded(); + mScrimController.transitionTo(mIsOccluded || qsExpanded ? + ScrimState.BOUNCER_OCCLUDED : ScrimState.BOUNCER); } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) { mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); } else if (mBrightnessMirrorVisible) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index 81641da4324c..e5fefd34ffb7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -126,7 +126,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mRipple = new KeyButtonRipple(context, this); - mVibratorHelper = new VibratorHelper(context); + mVibratorHelper = Dependency.get(VibratorHelper.class); mOverviewProxyService = Dependency.get(OverviewProxyService.class); setBackground(mRipple); } @@ -224,8 +224,10 @@ public class KeyButtonView extends ImageView implements ButtonInterface { case MotionEvent.ACTION_DOWN: mDownTime = SystemClock.uptimeMillis(); mLongClicked = false; - mTouchDownX = (int) ev.getX(); - mTouchDownY = (int) ev.getY(); + + // Use raw X and Y to detect gestures in case a parent changes the x and y values + mTouchDownX = (int) ev.getRawX(); + mTouchDownY = (int) ev.getRawY(); if (mCode != 0) { sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime); } else { @@ -241,8 +243,8 @@ public class KeyButtonView extends ImageView implements ButtonInterface { postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout()); break; case MotionEvent.ACTION_MOVE: - x = (int)ev.getX(); - y = (int)ev.getY(); + x = (int)ev.getRawX(); + y = (int)ev.getRawY(); boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > mTouchSlop; boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > mTouchSlop; if (exceededTouchSlopX || exceededTouchSlopY) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 487d1c5880a1..a0466754eb96 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -205,13 +205,15 @@ public class MobileSignalController extends SignalController< } MobileIconGroup hGroup = TelephonyIcons.THREE_G; + MobileIconGroup hPlusGroup = TelephonyIcons.THREE_G; if (mConfig.hspaDataDistinguishable) { hGroup = TelephonyIcons.H; + hPlusGroup = TelephonyIcons.H_PLUS; } mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup); mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup); mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup); - mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup); + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hPlusGroup); if (mConfig.show4gForLte) { mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 53637425401b..2258fa251800 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -884,6 +884,7 @@ public class NetworkControllerImpl extends BroadcastReceiver datatype.equals("e") ? TelephonyIcons.E : datatype.equals("g") ? TelephonyIcons.G : datatype.equals("h") ? TelephonyIcons.H : + datatype.equals("h+") ? TelephonyIcons.H_PLUS : datatype.equals("lte") ? TelephonyIcons.LTE : datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS : datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED : diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java index 986abef10031..7e6fe022644a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java @@ -28,7 +28,6 @@ class TelephonyIcons { static final int ICON_G = R.drawable.ic_g_mobiledata; static final int ICON_E = R.drawable.ic_e_mobiledata; static final int ICON_H = R.drawable.ic_h_mobiledata; - // TODO: add logic to insert H+ icon static final int ICON_H_PLUS = R.drawable.ic_h_plus_mobiledata; static final int ICON_3G = R.drawable.ic_3g_mobiledata; static final int ICON_4G = R.drawable.ic_4g_mobiledata; @@ -135,6 +134,19 @@ class TelephonyIcons { TelephonyIcons.ICON_H, false); + static final MobileIconGroup H_PLUS = new MobileIconGroup( + "H+", + null, + null, + AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH, + 0, 0, + 0, + 0, + AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0], + R.string.data_connection_3_5g_plus, + TelephonyIcons.ICON_H_PLUS, + false); + static final MobileIconGroup FOUR_G = new MobileIconGroup( "4G", null, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java index 8777aa6454bc..4ee805934522 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java @@ -35,6 +35,7 @@ public interface ZenModeController extends CallbackController<Callback> { boolean isCountdownConditionSupported(); int getCurrentUser(); boolean isVolumeRestricted(); + boolean areNotificationsHiddenInShade(); public static interface Callback { default void onZenChanged(int zen) {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java index 0fd244527540..a9da239ada9d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -33,13 +33,11 @@ import android.os.UserManager; import android.provider.Settings.Global; import android.provider.Settings.Secure; import android.service.notification.Condition; -import android.service.notification.IConditionListener; import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.ZenRule; -import android.support.annotation.VisibleForTesting; import android.util.Log; -import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.qs.GlobalSetting; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.util.Utils; @@ -64,9 +62,9 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode private final UserManager mUserManager; private int mUserId; - private boolean mRequesting; private boolean mRegistered; private ZenModeConfig mConfig; + private int mZenMode; public ZenModeControllerImpl(Context context, Handler handler) { super(context); @@ -74,6 +72,7 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) { @Override protected void handleValueChanged(int value) { + updateZenMode(value); fireZenChanged(value); } }; @@ -86,7 +85,9 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); mConfig = mNoMan.getZenModeConfig(); mModeSetting.setListening(true); + updateZenMode(mModeSetting.getValue()); mConfigSetting.setListening(true); + updateZenModeConfig(); mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mSetupObserver = new SetupObserver(handler); mSetupObserver.register(); @@ -101,6 +102,15 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode } @Override + public boolean areNotificationsHiddenInShade() { + if (mZenMode != Global.ZEN_MODE_OFF) { + return (mConfig.suppressedVisualEffects & NotificationManager.Policy + .SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0; + } + return false; + } + + @Override public void addCallback(Callback callback) { mCallbacks.add(callback); } @@ -186,10 +196,6 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode Utils.safeForeach(mCallbacks, c -> c.onZenAvailableChanged(available)); } - private void fireConditionsChanged(Condition[] conditions) { - Utils.safeForeach(mCallbacks, c -> c.onConditionsChanged(conditions)); - } - private void fireManualRuleChanged(ZenRule rule) { Utils.safeForeach(mCallbacks, c -> c.onManualRuleChanged(rule)); } @@ -199,17 +205,13 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode Utils.safeForeach(mCallbacks, c -> c.onConfigChanged(config)); } - private void updateConditions(Condition[] conditions) { - if (conditions == null || conditions.length == 0) return; - for (Condition c : conditions) { - if ((c.flags & Condition.FLAG_RELEVANT_NOW) == 0) continue; - mConditions.put(c.id, c); - } - fireConditionsChanged( - mConditions.values().toArray(new Condition[mConditions.values().size()])); + @VisibleForTesting + protected void updateZenMode(int mode) { + mZenMode = mode; } - private void updateZenModeConfig() { + @VisibleForTesting + protected void updateZenModeConfig() { final ZenModeConfig config = mNoMan.getZenModeConfig(); if (Objects.equals(config, mConfig)) return; final ZenRule oldRule = mConfig != null ? mConfig.manualRule : null; @@ -220,16 +222,6 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode fireManualRuleChanged(newRule); } - private final IConditionListener mListener = new IConditionListener.Stub() { - @Override - public void onConditionsReceived(Condition[] conditions) { - if (DEBUG) Slog.d(TAG, "onConditionsReceived " - + (conditions == null ? 0 : conditions.length) + " mRequesting=" + mRequesting); - if (!mRequesting) return; - updateConditions(conditions); - } - }; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 66fde7986b00..a85f4e2b53a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -104,7 +104,6 @@ import android.support.v4.graphics.ColorUtils; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; @@ -3985,6 +3984,11 @@ public class NotificationStackScrollLayout extends ViewGroup } else { mEmptyShadeView.setInvisible(); } + if (mStatusBar.areNotificationsHidden()) { + mEmptyShadeView.setText(R.string.dnd_suppressing_shade_text); + } else { + mEmptyShadeView.setText(R.string.empty_shade_text); + } mEmptyShadeView.setVisibility(newVisibility); mEmptyShadeView.setWillBeGone(false); updateContentHeight(); diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 22bf98378ccb..e94d6bd5ee99 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -479,6 +479,7 @@ public class VolumeDialogImpl implements VolumeDialog { if (mShowing) return; mShowing = true; + initSettingsH(); mDialog.show(); Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked()); mController.notifyVisible(true); @@ -896,6 +897,9 @@ public class VolumeDialogImpl implements VolumeDialog { } private String getStreamLabelH(StreamState ss) { + if (ss == null) { + return ""; + } if (ss.remoteLabel != null) { return ss.remoteLabel; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index b6116e00bac1..5812da29b2ab 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -21,7 +21,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; -import androidx.app.slice.Slice; +import androidx.slice.Slice; import android.app.AlarmManager; import android.content.ContentResolver; @@ -45,10 +45,10 @@ import org.mockito.MockitoAnnotations; import java.util.Arrays; import java.util.concurrent.TimeUnit; -import androidx.app.slice.SliceItem; -import androidx.app.slice.SliceProvider; -import androidx.app.slice.SliceSpecs; -import androidx.app.slice.core.SliceQuery; +import androidx.slice.SliceItem; +import androidx.slice.SliceProvider; +import androidx.slice.SliceSpecs; +import androidx.slice.core.SliceQuery; @SmallTest @RunWith(AndroidTestingRunner.class) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java index ec994a1a5650..5c347301bd8c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java @@ -17,7 +17,7 @@ package com.android.systemui.statusbar.policy; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent - .NOTIFICATION_SINCE_CREATE_MILLIS; + .RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS; import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.any; @@ -119,9 +119,9 @@ public class IconLoggerImplTest extends SysuiTestCase { verify(mMetricsLogger).write(argThat(maker -> { if (IconLoggerImpl.MIN_LOG_INTERVAL > - (long) maker.getTaggedData(NOTIFICATION_SINCE_CREATE_MILLIS)) { + (long) maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS)) { Log.e("IconLoggerImplTest", "Invalid latency " - + maker.getTaggedData(NOTIFICATION_SINCE_CREATE_MILLIS)); + + maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS)); return false; } if (1 != (int) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index 8629799faea0..365a9b28e8a8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -74,6 +74,17 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { verifyDataIndicators(TelephonyIcons.ICON_H); } + + @Test + public void testHspaPlusDataIcon() { + setupDefaultSignal(); + updateDataConnectionState(TelephonyManager.DATA_CONNECTED, + TelephonyManager.NETWORK_TYPE_HSPAP); + + verifyDataIndicators(TelephonyIcons.ICON_H_PLUS); + } + + @Test public void testWfcNoDataIcon() { setupDefaultSignal(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java index 8124bf39328b..da8017e25525 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java @@ -14,11 +14,17 @@ package com.android.systemui.statusbar.policy; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.app.NotificationManager; import android.os.Handler; +import android.provider.Settings; import android.service.notification.ZenModeConfig; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; @@ -27,8 +33,11 @@ import android.testing.TestableLooper.RunWithLooper; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.policy.ZenModeController.Callback; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -36,21 +45,64 @@ import org.junit.runner.RunWith; public class ZenModeControllerImplTest extends SysuiTestCase { private Callback mCallback; + @Mock + NotificationManager mNm; + @Mock + ZenModeConfig mConfig; + + private ZenModeControllerImpl mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext.addMockSystemService(NotificationManager.class, mNm); + when(mNm.getZenModeConfig()).thenReturn(mConfig); + + mController = new ZenModeControllerImpl(mContext, new Handler()); + } @Test public void testRemoveDuringCallback() { - ZenModeControllerImpl controller = new ZenModeControllerImpl(mContext, new Handler()); mCallback = new Callback() { @Override public void onConfigChanged(ZenModeConfig config) { - controller.removeCallback(mCallback); + mController.removeCallback(mCallback); } }; - controller.addCallback(mCallback); + mController.addCallback(mCallback); Callback mockCallback = mock(Callback.class); - controller.addCallback(mockCallback); - controller.fireConfigChanged(null); + mController.addCallback(mockCallback); + mController.fireConfigChanged(null); verify(mockCallback).onConfigChanged(eq(null)); } + @Test + public void testAreNotificationsHiddenInShade_zenOffShadeSuppressed() { + mConfig.suppressedVisualEffects = + NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; + mController.updateZenMode(Settings.Global.ZEN_MODE_OFF); + mController.updateZenModeConfig(); + + assertFalse(mController.areNotificationsHiddenInShade()); + } + + @Test + public void testAreNotificationsHiddenInShade_zenOnShadeNotSuppressed() { + mConfig.suppressedVisualEffects = + NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; + mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mController.updateZenModeConfig(); + + assertFalse(mController.areNotificationsHiddenInShade()); + } + + @Test + public void testAreNotificationsHiddenInShade_zenOnShadeSuppressed() { + mConfig.suppressedVisualEffects = + NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; + mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mController.updateZenModeConfig(); + + assertTrue(mController.areNotificationsHiddenInShade()); + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java index d9673d3552d8..6fa91ff07850 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java @@ -17,17 +17,16 @@ package com.android.systemui.statusbar.stack; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.annotation.UiThread; import android.support.test.annotation.UiThreadTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import android.view.NotificationHeaderView; -import android.view.View; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.NotificationTestHelper; +import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBar; @@ -72,4 +71,27 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { 0.01 /* delta */); } + @Test + public void updateEmptyView_dndSuppressing() { + EmptyShadeView view = mock(EmptyShadeView.class); + mStackScroller.setEmptyShadeView(view); + when(view.willBeGone()).thenReturn(true); + when(mBar.areNotificationsHidden()).thenReturn(true); + + mStackScroller.updateEmptyShadeView(true); + + verify(view).setText(R.string.dnd_suppressing_shade_text); + } + + @Test + public void updateEmptyView_dndNotSuppressing() { + EmptyShadeView view = mock(EmptyShadeView.class); + mStackScroller.setEmptyShadeView(view); + when(view.willBeGone()).thenReturn(true); + when(mBar.areNotificationsHidden()).thenReturn(false); + + mStackScroller.updateEmptyShadeView(true); + + verify(view).setText(R.string.empty_shade_text); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java index fb9bf7a15f60..86c43c998877 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java @@ -77,4 +77,9 @@ public class FakeZenModeController extends BaseLeakChecker<Callback> implements public boolean isVolumeRestricted() { return false; } + + @Override + public boolean areNotificationsHiddenInShade() { + return false; + } } diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk new file mode 100644 index 000000000000..d83b30a8785a --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_RRO_THEME := DisplayCutoutEmulationDouble +LOCAL_CERTIFICATE := platform + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_PACKAGE_NAME := DisplayCutoutEmulationDoubleOverlay +LOCAL_SDK_VERSION := current + +include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/AndroidManifest.xml new file mode 100644 index 000000000000..5d3385d17961 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/AndroidManifest.xml @@ -0,0 +1,26 @@ +<!-- + ~ Copyright (C) 2018 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.internal.display.cutout.emulation.double" + android:versionCode="1" + android:versionName="1.0"> + <overlay android:targetPackage="android" + android:category="com.android.internal.display_cutout_emulation" + android:priority="1"/> + + <application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/> +</manifest> diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml new file mode 100644 index 000000000000..ca261f98cfae --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml @@ -0,0 +1,67 @@ +<!-- + ~ Copyright (C) 2018 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- The bounding path of the cutout region of the main built-in display. + Must either be empty if there is no cutout region, or a string that is parsable by + {@link android.util.PathParser}. + + The path is assumed to be specified in display coordinates with pixel units and in + the display's native orientation, with the origin of the coordinate system at the + center top of the display. + + To facilitate writing device-independent emulation overlays, the marker `@dp` can be + appended after the path string to interpret coordinates in dp instead of px units. + Note that a physical cutout should be configured in pixels for the best results. + --> + <string translatable="false" name="config_mainBuiltInDisplayCutout"> + M 0,0 + L -72, 0 + L -69.9940446283, 20.0595537175 + C -69.1582133885, 28.4178661152 -65.2, 32.0 -56.8, 32.0 + L 56.8, 32.0 + C 65.2, 32.0 69.1582133885, 28.4178661152 69.9940446283, 20.0595537175 + L 72, 0 + Z + @bottom + M 0,0 + L -72, 0 + L -69.9940446283, -20.0595537175 + C -69.1582133885, -28.4178661152 -65.2, -32.0 -56.8, -32.0 + L 56.8, -32.0 + C 65.2, -32.0 69.1582133885, -28.4178661152 69.9940446283, -20.0595537175 + L 72, 0 + Z + @dp + </string> + + <!-- Whether the display cutout region of the main built-in display should be forced to + black in software (to avoid aliasing or emulate a cutout that is not physically existent). + --> + <bool name="config_fillMainBuiltInDisplayCutout">true</bool> + + <!-- Height of the status bar --> + <dimen name="status_bar_height_portrait">48dp</dimen> + <dimen name="status_bar_height_landscape">28dp</dimen> + <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> + <dimen name="quick_qs_offset_height">48dp</dimen> + <!-- Total height of QQS (quick_qs_offset_height + 128) --> + <dimen name="quick_qs_total_height">176dp</dimen> + +</resources> + + diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml new file mode 100644 index 000000000000..68c2dcbbe3f6 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <string name="display_cutout_emulation_overlay">Double display cutout</string> + +</resources> + diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 07012d87bbb4..e3be5d43a327 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5499,6 +5499,14 @@ message MetricsEvent { // OS: P SETTINGS_ZONE_PICKER_FIXED_OFFSET = 1357; + // Action: notification shade > manage notifications + // OS: P + ACTION_MANAGE_NOTIFICATIONS = 1358; + + // This value should never appear in log outputs - it is reserved for + // internal platform metrics use. + RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS = 1359; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/backup/java/com/android/server/backup/BackupManagerConstants.java b/services/backup/java/com/android/server/backup/BackupManagerConstants.java index 99160c24d3b4..dd6e6ab2ece1 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerConstants.java +++ b/services/backup/java/com/android/server/backup/BackupManagerConstants.java @@ -18,53 +18,76 @@ package com.android.server.backup; import android.app.AlarmManager; import android.content.ContentResolver; -import android.database.ContentObserver; -import android.net.Uri; import android.os.Handler; import android.provider.Settings; import android.text.TextUtils; import android.util.KeyValueListParser; +import android.util.KeyValueSettingObserver; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; /** * Class to access backup manager constants. * - * The backup manager constants are encoded as a key value list separated by commas - * and stored as a Settings.Secure. + * <p>The backup manager constants are encoded as a key value list separated by commas and stored as + * a Settings.Secure. */ -class BackupManagerConstants extends ContentObserver { +class BackupManagerConstants extends KeyValueSettingObserver { private static final String TAG = "BackupManagerConstants"; + private static final String SETTING = Settings.Secure.BACKUP_MANAGER_CONSTANTS; // Key names stored in the secure settings value. - private static final String KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS = + @VisibleForTesting + public static final String KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS = "key_value_backup_interval_milliseconds"; - private static final String KEY_VALUE_BACKUP_FUZZ_MILLISECONDS = + + @VisibleForTesting + public static final String KEY_VALUE_BACKUP_FUZZ_MILLISECONDS = "key_value_backup_fuzz_milliseconds"; - private static final String KEY_VALUE_BACKUP_REQUIRE_CHARGING = + + @VisibleForTesting + public static final String KEY_VALUE_BACKUP_REQUIRE_CHARGING = "key_value_backup_require_charging"; - private static final String KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE = + + @VisibleForTesting + public static final String KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE = "key_value_backup_required_network_type"; - private static final String FULL_BACKUP_INTERVAL_MILLISECONDS = + + @VisibleForTesting + public static final String FULL_BACKUP_INTERVAL_MILLISECONDS = "full_backup_interval_milliseconds"; - private static final String FULL_BACKUP_REQUIRE_CHARGING = - "full_backup_require_charging"; - private static final String FULL_BACKUP_REQUIRED_NETWORK_TYPE = + + @VisibleForTesting + public static final String FULL_BACKUP_REQUIRE_CHARGING = "full_backup_require_charging"; + + @VisibleForTesting + public static final String FULL_BACKUP_REQUIRED_NETWORK_TYPE = "full_backup_required_network_type"; - private static final String BACKUP_FINISHED_NOTIFICATION_RECEIVERS = + + @VisibleForTesting + public static final String BACKUP_FINISHED_NOTIFICATION_RECEIVERS = "backup_finished_notification_receivers"; // Hard coded default values. - private static final long DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS = + @VisibleForTesting + public static final long DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS = 4 * AlarmManager.INTERVAL_HOUR; - private static final long DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS = - 10 * 60 * 1000; - private static final boolean DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING = true; - private static final int DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE = 1; - private static final long DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS = + + @VisibleForTesting + public static final long DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS = 10 * 60 * 1000; + + @VisibleForTesting public static final boolean DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING = true; + @VisibleForTesting public static final int DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE = 1; + + @VisibleForTesting + public static final long DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS = 24 * AlarmManager.INTERVAL_HOUR; - private static final boolean DEFAULT_FULL_BACKUP_REQUIRE_CHARGING = true; - private static final int DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE = 2; - private static final String DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS = ""; + + @VisibleForTesting public static final boolean DEFAULT_FULL_BACKUP_REQUIRE_CHARGING = true; + @VisibleForTesting public static final int DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE = 2; + + @VisibleForTesting + public static final String DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS = ""; // Backup manager constants. private long mKeyValueBackupIntervalMilliseconds; @@ -76,49 +99,46 @@ class BackupManagerConstants extends ContentObserver { private int mFullBackupRequiredNetworkType; private String[] mBackupFinishedNotificationReceivers; - private ContentResolver mResolver; - private final KeyValueListParser mParser = new KeyValueListParser(','); - public BackupManagerConstants(Handler handler, ContentResolver resolver) { - super(handler); - mResolver = resolver; - updateSettings(); - mResolver.registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.BACKUP_MANAGER_CONSTANTS), false, this); + super(handler, resolver, Settings.Secure.getUriFor(SETTING)); } - @Override - public void onChange(boolean selfChange, Uri uri) { - updateSettings(); + public String getSettingValue(ContentResolver resolver) { + return Settings.Secure.getString(resolver, SETTING); } - private synchronized void updateSettings() { - try { - mParser.setString(Settings.Secure.getString(mResolver, - Settings.Secure.BACKUP_MANAGER_CONSTANTS)); - } catch (IllegalArgumentException e) { - // Failed to parse the settings string. Use defaults. - Slog.e(TAG, "Bad backup manager constants: " + e.getMessage()); - } - - mKeyValueBackupIntervalMilliseconds = mParser.getLong( - KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS, - DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS); - mKeyValueBackupFuzzMilliseconds = mParser.getLong(KEY_VALUE_BACKUP_FUZZ_MILLISECONDS, - DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS); - mKeyValueBackupRequireCharging = mParser.getBoolean(KEY_VALUE_BACKUP_REQUIRE_CHARGING, - DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING); - mKeyValueBackupRequiredNetworkType = mParser.getInt(KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE, - DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE); - mFullBackupIntervalMilliseconds = mParser.getLong(FULL_BACKUP_INTERVAL_MILLISECONDS, - DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS); - mFullBackupRequireCharging = mParser.getBoolean(FULL_BACKUP_REQUIRE_CHARGING, - DEFAULT_FULL_BACKUP_REQUIRE_CHARGING); - mFullBackupRequiredNetworkType = mParser.getInt(FULL_BACKUP_REQUIRED_NETWORK_TYPE, - DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE); - String backupFinishedNotificationReceivers = mParser.getString( - BACKUP_FINISHED_NOTIFICATION_RECEIVERS, - DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS); + public synchronized void update(KeyValueListParser parser) { + mKeyValueBackupIntervalMilliseconds = + parser.getLong( + KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS, + DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS); + mKeyValueBackupFuzzMilliseconds = + parser.getLong( + KEY_VALUE_BACKUP_FUZZ_MILLISECONDS, + DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS); + mKeyValueBackupRequireCharging = + parser.getBoolean( + KEY_VALUE_BACKUP_REQUIRE_CHARGING, + DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING); + mKeyValueBackupRequiredNetworkType = + parser.getInt( + KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE, + DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE); + mFullBackupIntervalMilliseconds = + parser.getLong( + FULL_BACKUP_INTERVAL_MILLISECONDS, + DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS); + mFullBackupRequireCharging = + parser.getBoolean( + FULL_BACKUP_REQUIRE_CHARGING, DEFAULT_FULL_BACKUP_REQUIRE_CHARGING); + mFullBackupRequiredNetworkType = + parser.getInt( + FULL_BACKUP_REQUIRED_NETWORK_TYPE, + DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE); + String backupFinishedNotificationReceivers = + parser.getString( + BACKUP_FINISHED_NOTIFICATION_RECEIVERS, + DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS); if (backupFinishedNotificationReceivers.isEmpty()) { mBackupFinishedNotificationReceivers = new String[] {}; } else { @@ -132,40 +152,50 @@ class BackupManagerConstants extends ContentObserver { // a reference of this object. public synchronized long getKeyValueBackupIntervalMilliseconds() { if (BackupManagerService.DEBUG_SCHEDULING) { - Slog.v(TAG, "getKeyValueBackupIntervalMilliseconds(...) returns " - + mKeyValueBackupIntervalMilliseconds); + Slog.v( + TAG, + "getKeyValueBackupIntervalMilliseconds(...) returns " + + mKeyValueBackupIntervalMilliseconds); } return mKeyValueBackupIntervalMilliseconds; } public synchronized long getKeyValueBackupFuzzMilliseconds() { if (BackupManagerService.DEBUG_SCHEDULING) { - Slog.v(TAG, "getKeyValueBackupFuzzMilliseconds(...) returns " - + mKeyValueBackupFuzzMilliseconds); + Slog.v( + TAG, + "getKeyValueBackupFuzzMilliseconds(...) returns " + + mKeyValueBackupFuzzMilliseconds); } return mKeyValueBackupFuzzMilliseconds; } public synchronized boolean getKeyValueBackupRequireCharging() { if (BackupManagerService.DEBUG_SCHEDULING) { - Slog.v(TAG, "getKeyValueBackupRequireCharging(...) returns " - + mKeyValueBackupRequireCharging); + Slog.v( + TAG, + "getKeyValueBackupRequireCharging(...) returns " + + mKeyValueBackupRequireCharging); } return mKeyValueBackupRequireCharging; } public synchronized int getKeyValueBackupRequiredNetworkType() { if (BackupManagerService.DEBUG_SCHEDULING) { - Slog.v(TAG, "getKeyValueBackupRequiredNetworkType(...) returns " - + mKeyValueBackupRequiredNetworkType); + Slog.v( + TAG, + "getKeyValueBackupRequiredNetworkType(...) returns " + + mKeyValueBackupRequiredNetworkType); } return mKeyValueBackupRequiredNetworkType; } public synchronized long getFullBackupIntervalMilliseconds() { if (BackupManagerService.DEBUG_SCHEDULING) { - Slog.v(TAG, "getFullBackupIntervalMilliseconds(...) returns " - + mFullBackupIntervalMilliseconds); + Slog.v( + TAG, + "getFullBackupIntervalMilliseconds(...) returns " + + mFullBackupIntervalMilliseconds); } return mFullBackupIntervalMilliseconds; } @@ -179,19 +209,21 @@ class BackupManagerConstants extends ContentObserver { public synchronized int getFullBackupRequiredNetworkType() { if (BackupManagerService.DEBUG_SCHEDULING) { - Slog.v(TAG, "getFullBackupRequiredNetworkType(...) returns " - + mFullBackupRequiredNetworkType); + Slog.v( + TAG, + "getFullBackupRequiredNetworkType(...) returns " + + mFullBackupRequiredNetworkType); } return mFullBackupRequiredNetworkType; } - /** - * Returns an array of package names that should be notified whenever a backup finishes. - */ + /** Returns an array of package names that should be notified whenever a backup finishes. */ public synchronized String[] getBackupFinishedNotificationReceivers() { if (BackupManagerService.DEBUG_SCHEDULING) { - Slog.v(TAG, "getBackupFinishedNotificationReceivers(...) returns " - + TextUtils.join(", ", mBackupFinishedNotificationReceivers)); + Slog.v( + TAG, + "getBackupFinishedNotificationReceivers(...) returns " + + TextUtils.join(", ", mBackupFinishedNotificationReceivers)); } return mBackupFinishedNotificationReceivers; } diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 646909177e72..d6f6c6cf1fc3 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -851,6 +851,10 @@ public class BackupManagerService implements BackupManagerServiceInterface { mJournal = null; // will be created on first use mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver()); + // We are observing changes to the constants throughout the lifecycle of BMS. This is + // because we reference the constants in multiple areas of BMS, which otherwise would + // require frequent starting and stopping. + mConstants.start(); // Set up the various sorts of package tracking we do mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); @@ -1394,7 +1398,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { // Returns the set of all applications that define an android:backupAgent attribute private List<PackageInfo> allAgentPackages() { // !!! TODO: cache this and regenerate only when necessary - int flags = PackageManager.GET_SIGNATURES; + int flags = PackageManager.GET_SIGNING_CERTIFICATES; List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags); int N = packages.size(); for (int a = N - 1; a >= 0; a--) { @@ -1639,7 +1643,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { } try { PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, - PackageManager.GET_SIGNATURES); + PackageManager.GET_SIGNING_CERTIFICATES); if (!AppBackupUtils.appIsEligibleForBackup(packageInfo.applicationInfo, mPackageManager)) { BackupObserverUtils.sendBackupOnPackageResult(observer, packageName, @@ -2349,7 +2353,8 @@ public class BackupManagerService implements BackupManagerServiceInterface { if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName); PackageInfo info; try { - info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + info = mPackageManager.getPackageInfo(packageName, + PackageManager.GET_SIGNING_CERTIFICATES); } catch (NameNotFoundException e) { Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data"); return; diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java index 3cf374faada4..dc28cd179bcb 100644 --- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java +++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java @@ -23,6 +23,7 @@ import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; @@ -30,6 +31,7 @@ import android.os.Build; import android.os.ParcelFileDescriptor; import android.util.Slog; +import com.android.server.LocalServices; import com.android.server.backup.utils.AppBackupUtils; import java.io.BufferedInputStream; @@ -154,7 +156,7 @@ public class PackageManagerBackupAgent extends BackupAgent { public static List<PackageInfo> getStorableApplications(PackageManager pm) { List<PackageInfo> pkgs; - pkgs = pm.getInstalledPackages(PackageManager.GET_SIGNATURES); + pkgs = pm.getInstalledPackages(PackageManager.GET_SIGNING_CERTIFICATES); int N = pkgs.size(); for (int a = N-1; a >= 0; a--) { PackageInfo pkg = pkgs.get(a); @@ -235,10 +237,17 @@ public class PackageManagerBackupAgent extends BackupAgent { if (home != null) { try { homeInfo = mPackageManager.getPackageInfo(home.getPackageName(), - PackageManager.GET_SIGNATURES); + PackageManager.GET_SIGNING_CERTIFICATES); homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName()); homeVersion = homeInfo.getLongVersionCode(); - homeSigHashes = BackupUtils.hashSignatureArray(homeInfo.signatures); + Signature[][] signingHistory = homeInfo.signingCertificateHistory; + if (signingHistory == null || signingHistory.length == 0) { + Slog.e(TAG, "Home app has no signing history"); + } else { + // retrieve the newest sigs to back up + Signature[] homeInfoSignatures = signingHistory[signingHistory.length - 1]; + homeSigHashes = BackupUtils.hashSignatureArray(homeInfoSignatures); + } } catch (NameNotFoundException e) { Slog.w(TAG, "Can't access preferred home info"); // proceed as though there were no preferred home set @@ -252,10 +261,11 @@ public class PackageManagerBackupAgent extends BackupAgent { // 2. the home app [or absence] we now use differs from the prior state, // OR 3. it looks like we use the same home app + version as before, but // the signatures don't match so we treat them as different apps. + PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); final boolean needHomeBackup = (homeVersion != mStoredHomeVersion) || !Objects.equals(home, mStoredHomeComponent) || (home != null - && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo)); + && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo, pmi)); if (needHomeBackup) { if (DEBUG) { Slog.i(TAG, "Home preference changed; backing up new state " + home); @@ -304,7 +314,7 @@ public class PackageManagerBackupAgent extends BackupAgent { PackageInfo info = null; try { info = mPackageManager.getPackageInfo(packName, - PackageManager.GET_SIGNATURES); + PackageManager.GET_SIGNING_CERTIFICATES); } catch (NameNotFoundException e) { // Weird; we just found it, and now are told it doesn't exist. // Treat it as having been removed from the device. @@ -323,9 +333,9 @@ public class PackageManagerBackupAgent extends BackupAgent { continue; } } - - if (info.signatures == null || info.signatures.length == 0) - { + + Signature[][] signingHistory = info.signingCertificateHistory; + if (signingHistory == null || signingHistory.length == 0) { Slog.w(TAG, "Not backing up package " + packName + " since it appears to have no signatures."); continue; @@ -347,8 +357,10 @@ public class PackageManagerBackupAgent extends BackupAgent { } else { outputBufferStream.writeInt(info.versionCode); } + // retrieve the newest sigs to back up + Signature[] infoSignatures = signingHistory[signingHistory.length - 1]; writeSignatureHashArray(outputBufferStream, - BackupUtils.hashSignatureArray(info.signatures)); + BackupUtils.hashSignatureArray(infoSignatures)); if (DEBUG) { Slog.v(TAG, "+ writing metadata for " + packName diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java index 2e2d3eb4ad21..821cca16bf60 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java @@ -129,7 +129,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor try { PackageInfo info = backupManagerService.getPackageManager().getPackageInfo( pkgName, - PackageManager.GET_SIGNATURES); + PackageManager.GET_SIGNING_CERTIFICATES); set.put(pkgName, info); } catch (NameNotFoundException e) { Slog.w(TAG, "Unknown package " + pkgName + ", skipping"); @@ -240,7 +240,8 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor // doAllApps supersedes the package set if any if (mAllApps) { - List<PackageInfo> allPackages = pm.getInstalledPackages(PackageManager.GET_SIGNATURES); + List<PackageInfo> allPackages = pm.getInstalledPackages( + PackageManager.GET_SIGNING_CERTIFICATES); for (int i = 0; i < allPackages.size(); i++) { PackageInfo pkg = allPackages.get(i); // Exclude system apps if we've been asked to do so diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index f9c366998ad2..2c2dd8528cb1 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -181,7 +181,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba for (String pkg : whichPackages) { try { PackageManager pm = backupManagerService.getPackageManager(); - PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES); + PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNING_CERTIFICATES); mCurrentPackage = info; if (!AppBackupUtils.appIsEligibleForBackup(info.applicationInfo, pm)) { // Cull any packages that have indicated that backups are not permitted, diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java index 0ba83cfeb361..11394e66a0f0 100644 --- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java +++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java @@ -422,7 +422,8 @@ public class PerformBackupTask implements BackupRestoreTask { // package's backup agent. try { PackageManager pm = backupManagerService.getPackageManager(); - mCurrentPackage = pm.getPackageInfo(request.packageName, PackageManager.GET_SIGNATURES); + mCurrentPackage = pm.getPackageInfo(request.packageName, + PackageManager.GET_SIGNING_CERTIFICATES); if (!AppBackupUtils.appIsEligibleForBackup(mCurrentPackage.applicationInfo, pm)) { // The manifest has changed but we had a stale backup request pending. // This won't happen again because the app won't be requesting further diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index 0ca4f25093ce..c1a1c1dc10e7 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -36,11 +36,13 @@ import android.app.backup.IFullBackupRestoreObserver; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Slog; +import com.android.server.LocalServices; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.FileMetadata; import com.android.server.backup.KeyValueAdbRestoreEngine; @@ -207,8 +209,11 @@ public class FullRestoreEngine extends RestoreEngine { if (info.path.equals(BACKUP_MANIFEST_FILENAME)) { Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures( info); + PackageManagerInternal pmi = LocalServices.getService( + PackageManagerInternal.class); RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( - mBackupManagerService.getPackageManager(), allowApks, info, signatures); + mBackupManagerService.getPackageManager(), allowApks, info, signatures, + pmi); mManifestSignatures.put(info.packageName, signatures); mPackagePolicies.put(pkg, restorePolicy); mPackageInstallers.put(pkg, info.installerPackageName); diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java index e576b3c32859..dacde0b9af68 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java @@ -40,6 +40,7 @@ import android.app.backup.IFullBackupRestoreObserver; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Environment; import android.os.ParcelFileDescriptor; @@ -47,6 +48,7 @@ import android.os.RemoteException; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; import com.android.server.backup.BackupManagerService; import com.android.server.backup.FileMetadata; import com.android.server.backup.KeyValueAdbRestoreEngine; @@ -470,9 +472,11 @@ public class PerformAdbRestoreTask implements Runnable { if (info.path.equals(BACKUP_MANIFEST_FILENAME)) { Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures( info); + PackageManagerInternal pmi = LocalServices.getService( + PackageManagerInternal.class); RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( mBackupManagerService.getPackageManager(), allowApks, - info, signatures); + info, signatures, pmi); mManifestSignatures.put(info.packageName, signatures); mPackagePolicies.put(pkg, restorePolicy); mPackageInstallers.put(pkg, info.installerPackageName); diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 3caa1e7fab79..4b467e5a0399 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -43,6 +43,7 @@ import android.app.backup.RestoreDescription; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.Message; @@ -57,6 +58,7 @@ import android.util.Slog; import com.android.internal.backup.IBackupTransport; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.BackupUtils; import com.android.server.backup.PackageManagerBackupAgent; @@ -504,7 +506,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { try { mCurrentPackage = backupManagerService.getPackageManager().getPackageInfo( - pkgName, PackageManager.GET_SIGNATURES); + pkgName, PackageManager.GET_SIGNING_CERTIFICATES); } catch (NameNotFoundException e) { // Whoops, we thought we could restore this package but it // turns out not to be present. Skip it. @@ -619,7 +621,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { } Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName); - if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) { + PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); + if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage, pmi)) { Slog.w(TAG, "Signature mismatch restoring " + packageName); mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH, mCurrentPackage, diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java index 6780563120e3..5518374ebdbc 100644 --- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java @@ -25,6 +25,7 @@ import android.app.backup.BackupTransport; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Process; import android.util.Slog; @@ -37,6 +38,9 @@ import com.android.server.backup.transport.TransportClient; * Utility methods wrapping operations on ApplicationInfo and PackageInfo. */ public class AppBackupUtils { + + private static final boolean DEBUG = false; + /** * Returns whether app is eligible for backup. * @@ -88,7 +92,8 @@ public class AppBackupUtils { public static boolean appIsRunningAndEligibleForBackupWithTransport( @Nullable TransportClient transportClient, String packageName, PackageManager pm) { try { - PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + PackageInfo packageInfo = pm.getPackageInfo(packageName, + PackageManager.GET_SIGNING_CERTIFICATES); ApplicationInfo applicationInfo = packageInfo.applicationInfo; if (!appIsEligibleForBackup(applicationInfo, pm) || appIsStopped(applicationInfo) @@ -165,13 +170,19 @@ public class AppBackupUtils { * * <ul> * <li>Source and target have at least one signature each - * <li>Target contains all signatures in source + * <li>Target contains all signatures in source, and nothing more * </ul> * + * or if both source and target have exactly one signature, and they don't match, we check + * if the app was ever signed with source signature (i.e. app has rotated key) + * Note: key rotation is only supported for apps ever signed with one key, and those apps will + * not be allowed to be signed by more certificates in the future + * * Note that if {@param target} is null we return false. */ - public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) { - if (target == null) { + public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target, + PackageManagerInternal pmi) { + if (target == null || target.packageName == null) { return false; } @@ -187,33 +198,52 @@ public class AppBackupUtils { return true; } - Signature[] deviceSigs = target.signatures; - if (MORE_DEBUG) { - Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceSigs); + // Don't allow unsigned apps on either end + if (ArrayUtils.isEmpty(storedSigs)) { + return false; } - // Don't allow unsigned apps on either end - if (ArrayUtils.isEmpty(storedSigs) || ArrayUtils.isEmpty(deviceSigs)) { + Signature[][] deviceHistorySigs = target.signingCertificateHistory; + if (ArrayUtils.isEmpty(deviceHistorySigs)) { + Slog.w(TAG, "signingCertificateHistory is empty, app was either unsigned or the flag" + + " PackageManager#GET_SIGNING_CERTIFICATES was not specified"); return false; } - // Signatures can be added over time, so the target-device apk needs to contain all the - // source-device apk signatures, but not necessarily the other way around. - int nStored = storedSigs.length; - int nDevice = deviceSigs.length; - - for (int i = 0; i < nStored; i++) { - boolean match = false; - for (int j = 0; j < nDevice; j++) { - if (storedSigs[i].equals(deviceSigs[j])) { - match = true; - break; + if (DEBUG) { + Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceHistorySigs); + } + + final int nStored = storedSigs.length; + if (nStored == 1) { + // if the app is only signed with one sig, it's possible it has rotated its key + // (the checks with signing history are delegated to PackageManager) + // TODO(b/73988180): address the case that app has declared restoreAnyVersion and is + // restoring from higher version to lower after having rotated the key (i.e. higher + // version has different sig than lower version that we want to restore to) + return pmi.isDataRestoreSafe(storedSigs[0], target.packageName); + } else { + // the app couldn't have rotated keys, since it was signed with multiple sigs - do + // a check to see if we find a match for all stored sigs + // since app hasn't rotated key, we only need to check with deviceHistorySigs[0] + Signature[] deviceSigs = deviceHistorySigs[0]; + int nDevice = deviceSigs.length; + + // ensure that each stored sig matches an on-device sig + for (int i = 0; i < nStored; i++) { + boolean match = false; + for (int j = 0; j < nDevice; j++) { + if (storedSigs[i].equals(deviceSigs[j])) { + match = true; + break; + } + } + if (!match) { + return false; } } - if (!match) { - return false; - } + // we have found a match for all stored sigs + return true; } - return true; } } diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java index d2ab09996d68..994d5a967298 100644 --- a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java @@ -104,11 +104,16 @@ public class FullBackupUtils { printer.println((installerName != null) ? installerName : ""); printer.println(withApk ? "1" : "0"); - if (pkg.signatures == null) { + + // write the signature block + Signature[][] signingHistory = pkg.signingCertificateHistory; + if (signingHistory == null) { printer.println("0"); } else { - printer.println(Integer.toString(pkg.signatures.length)); - for (Signature sig : pkg.signatures) { + // retrieve the newest sigs to write + Signature[] signatures = signingHistory[signingHistory.length - 1]; + printer.println(Integer.toString(signatures.length)); + for (Signature sig : signatures) { printer.println(sig.toCharsString()); } } diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java index 10f06954f17f..df7e6d45ba0f 100644 --- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java +++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java @@ -30,6 +30,7 @@ import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.Session; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Bundle; import android.os.IBinder; @@ -37,6 +38,7 @@ import android.os.Process; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.server.LocalServices; import com.android.server.backup.FileMetadata; import com.android.server.backup.restore.RestoreDeleteObserver; import com.android.server.backup.restore.RestorePolicy; @@ -142,9 +144,8 @@ public class RestoreUtils { uninstall = true; } else { try { - PackageInfo pkg = packageManager.getPackageInfo( - info.packageName, - PackageManager.GET_SIGNATURES); + PackageInfo pkg = packageManager.getPackageInfo(info.packageName, + PackageManager.GET_SIGNING_CERTIFICATES); if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { Slog.w(TAG, "Restore stream contains apk of package " @@ -154,7 +155,9 @@ public class RestoreUtils { } else { // So far so good -- do the signatures match the manifest? Signature[] sigs = manifestSignatures.get(info.packageName); - if (AppBackupUtils.signaturesMatch(sigs, pkg)) { + PackageManagerInternal pmi = LocalServices.getService( + PackageManagerInternal.class); + if (AppBackupUtils.signaturesMatch(sigs, pkg, pmi)) { // If this is a system-uid app without a declared backup agent, // don't restore any of the file data. if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID) diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java index cc26ff8b5090..6dd5284879f0 100644 --- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java +++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java @@ -50,6 +50,7 @@ import android.app.backup.IBackupManagerMonitor; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Bundle; import android.os.Process; @@ -385,7 +386,8 @@ public class TarBackupReader { * @return a restore policy constant. */ public RestorePolicy chooseRestorePolicy(PackageManager packageManager, - boolean allowApks, FileMetadata info, Signature[] signatures) { + boolean allowApks, FileMetadata info, Signature[] signatures, + PackageManagerInternal pmi) { if (signatures == null) { return RestorePolicy.IGNORE; } @@ -395,7 +397,7 @@ public class TarBackupReader { // Okay, got the manifest info we need... try { PackageInfo pkgInfo = packageManager.getPackageInfo( - info.packageName, PackageManager.GET_SIGNATURES); + info.packageName, PackageManager.GET_SIGNING_CERTIFICATES); // Fall through to IGNORE if the app explicitly disallows backup final int flags = pkgInfo.applicationInfo.flags; if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { @@ -411,7 +413,7 @@ public class TarBackupReader { // such packages are signed with the platform cert instead of // the app developer's cert, so they're different on every // device. - if (AppBackupUtils.signaturesMatch(signatures, pkgInfo)) { + if (AppBackupUtils.signaturesMatch(signatures, pkgInfo, pmi)) { if ((pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) { Slog.i(TAG, "Package has restoreAnyVersion; taking data"); diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 15f3a2362043..ecf80ba73683 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -610,7 +610,7 @@ public class AppOpsService extends IAppOpsService.Stub { @Override public void setUidMode(int code, int uid, int mode) { if (Binder.getCallingPid() != Process.myPid()) { - mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, + mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES, Binder.getCallingPid(), Binder.getCallingUid(), null); } verifyIncomingOp(code); @@ -714,7 +714,7 @@ public class AppOpsService extends IAppOpsService.Stub { @Override public void setMode(int code, int uid, String packageName, int mode) { if (Binder.getCallingPid() != Process.myPid()) { - mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, + mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES, Binder.getCallingPid(), Binder.getCallingUid(), null); } verifyIncomingOp(code); @@ -832,7 +832,7 @@ public class AppOpsService extends IAppOpsService.Stub { public void resetAllModes(int reqUserId, String reqPackageName) { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); - mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, + mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES, callingPid, callingUid, null); reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId, true, true, "resetAllModes", null); @@ -1087,6 +1087,8 @@ public class AppOpsService extends IAppOpsService.Stub { String[] exceptionPackages) { verifyIncomingUid(uid); verifyIncomingOp(code); + mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES, + Binder.getCallingPid(), Binder.getCallingUid(), null); synchronized (this) { SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code); if (usageRestrictions == null) { @@ -2330,7 +2332,7 @@ public class AppOpsService extends IAppOpsService.Stub { } case "write-settings": { shell.mInternal.mContext.enforcePermission( - android.Manifest.permission.UPDATE_APP_OPS_STATS, + android.Manifest.permission.MANAGE_APP_OPS_MODES, Binder.getCallingPid(), Binder.getCallingUid(), null); long token = Binder.clearCallingIdentity(); try { @@ -2346,7 +2348,7 @@ public class AppOpsService extends IAppOpsService.Stub { } case "read-settings": { shell.mInternal.mContext.enforcePermission( - android.Manifest.permission.UPDATE_APP_OPS_STATS, + android.Manifest.permission.MANAGE_APP_OPS_MODES, Binder.getCallingPid(), Binder.getCallingUid(), null); long token = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 62e82a064db2..38968712f4c8 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -65,7 +65,6 @@ import com.android.server.am.BatteryStatsService; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.NoSuchElementException; @@ -164,14 +163,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private int[] mDataActivity; + // Connection state of default APN type data (i.e. internet) of phones private int[] mDataConnectionState; - private ArrayList<String>[] mConnectedApns; - - private LinkProperties[] mDataConnectionLinkProperties; - - private NetworkCapabilities[] mDataConnectionNetworkCapabilities; - private Bundle[] mCellLocation; private int[] mDataConnectionNetworkType; @@ -323,9 +317,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mBatteryStats = BatteryStatsService.getService(); int numPhones = TelephonyManager.getDefault().getPhoneCount(); - if (DBG) log("TelephonyRegistor: ctor numPhones=" + numPhones); + if (DBG) log("TelephonyRegistry: ctor numPhones=" + numPhones); mNumPhones = numPhones; - mConnectedApns = new ArrayList[numPhones]; mCallState = new int[numPhones]; mDataActivity = new int[numPhones]; mDataConnectionState = new int[numPhones]; @@ -339,8 +332,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mMessageWaiting = new boolean[numPhones]; mCallForwarding = new boolean[numPhones]; mCellLocation = new Bundle[numPhones]; - mDataConnectionLinkProperties = new LinkProperties[numPhones]; - mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones]; mCellInfo = new ArrayList<List<CellInfo>>(); mPhysicalChannelConfigs = new ArrayList<List<PhysicalChannelConfig>>(); for (int i = 0; i < numPhones; i++) { @@ -358,7 +349,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mCellLocation[i] = new Bundle(); mCellInfo.add(i, null); mPhysicalChannelConfigs.add(i, null); - mConnectedApns[i] = new ArrayList<String>(); } // Note that location can be null for non-phone builds like @@ -1219,36 +1209,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { int phoneId = SubscriptionManager.getPhoneId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { - boolean modified = false; - if (state == TelephonyManager.DATA_CONNECTED) { - if (!mConnectedApns[phoneId].contains(apnType)) { - mConnectedApns[phoneId].add(apnType); - if (mDataConnectionState[phoneId] != state) { - mDataConnectionState[phoneId] = state; - modified = true; - } - } - } else { - if (mConnectedApns[phoneId].remove(apnType)) { - if (mConnectedApns[phoneId].isEmpty()) { - mDataConnectionState[phoneId] = state; - modified = true; - } else { - // leave mDataConnectionState as is and - // send out the new status for the APN in question. - } - } - } - mDataConnectionLinkProperties[phoneId] = linkProperties; - mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities; - if (mDataConnectionNetworkType[phoneId] != networkType) { - mDataConnectionNetworkType[phoneId] = networkType; - // need to tell registered listeners about the new network type - modified = true; - } - if (modified) { - String str = "onDataConnectionStateChanged(" + mDataConnectionState[phoneId] - + ", " + mDataConnectionNetworkType[phoneId] + ")"; + // We only call the callback when the change is for default APN type. + if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType) + && (mDataConnectionState[phoneId] != state + || mDataConnectionNetworkType[phoneId] != networkType)) { + String str = "onDataConnectionStateChanged(" + state + + ", " + networkType + ")"; log(str); mLocalLog.log(str); for (Record r : mRecords) { @@ -1259,15 +1225,16 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (DBG) { log("Notify data connection state changed on sub: " + subId); } - r.callback.onDataConnectionStateChanged( - mDataConnectionState[phoneId], - mDataConnectionNetworkType[phoneId]); + r.callback.onDataConnectionStateChanged(state, networkType); } catch (RemoteException ex) { mRemoveList.add(r.binder); } } } handleRemoveListLocked(); + + mDataConnectionState[phoneId] = state; + mDataConnectionNetworkType[phoneId] = networkType; } mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType, apnType, apn, reason, linkProperties, ""); @@ -1503,14 +1470,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mCallForwarding=" + mCallForwarding[i]); pw.println("mDataActivity=" + mDataActivity[i]); pw.println("mDataConnectionState=" + mDataConnectionState[i]); - pw.println("mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]); - pw.println("mDataConnectionNetworkCapabilities=" + - mDataConnectionNetworkCapabilities[i]); pw.println("mCellLocation=" + mCellLocation[i]); pw.println("mCellInfo=" + mCellInfo.get(i)); pw.decreaseIndent(); } - pw.println("mConnectedApns=" + Arrays.toString(mConnectedApns)); pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState); pw.println("mPreciseCallState=" + mPreciseCallState); pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 26f83f560c5c..eb4e32e47489 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -3390,10 +3390,15 @@ public final class ActiveServices { return; } + app = r.app; + if (app != null && app.debugging) { + // The app's being debugged; let it ride + return; + } + if (DEBUG_BACKGROUND_CHECK) { Slog.i(TAG, "Service foreground-required timeout for " + r); } - app = r.app; r.fgWaiting = false; stopServiceLocked(r); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c1c68e8554e8..96633da16508 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5401,11 +5401,12 @@ public class ActivityManagerService extends IActivityManager.Stub final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); + final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(bOptions); final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { return mStackSupervisor.startActivityFromRecents(callingPid, callingUid, taskId, - SafeActivityOptions.fromBundle(bOptions)); + safeOptions); } } finally { Binder.restoreCallingIdentity(origId); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index e38be67f7b69..8c49472b58c6 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1621,12 +1621,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo return; } - if (isState(DESTROYED) || (state != DESTROYED && isState(DESTROYING))) { - // We cannot move backwards from destroyed and destroying states. - throw new IllegalArgumentException("cannot move back states once destroying" - + "current:" + mState + " requested:" + state); - } - final ActivityState prev = mState; mState = state; @@ -1641,23 +1635,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (parent != null) { parent.onActivityStateChanged(this, state, reason); } - - if (isState(DESTROYING, DESTROYED)) { - makeFinishingLocked(); - - // When moving to the destroyed state, immediately destroy the activity in the - // associated stack. Most paths for finishing an activity will handle an activity's path - // to destroy through mechanisms such as ActivityStackSupervisor#mFinishingActivities. - // However, moving to the destroyed state directly (as in the case of an app dying) and - // marking it as finished will lead to cleanup steps that will prevent later handling - // from happening. - if (isState(DESTROYED)) { - final ActivityStack stack = getStack(); - if (stack != null) { - stack.activityDestroyedLocked(this, reason); - } - } - } } ActivityState getState() { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 2d7520eacafa..2c4eac0e391b 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2707,9 +2707,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to " + lastState + ": " + next); next.setState(lastState, "resumeTopActivityInnerLocked"); - if (lastStack != null) { + + // lastResumedActivity being non-null implies there is a lastStack present. + if (lastResumedActivity != null) { lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked"); } + Slog.i(TAG, "Restarting because process died: " + next); if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; @@ -3811,14 +3814,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final ActivityState prevState = r.getState(); if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r); - // We are already destroying / have already destroyed the activity. Do not continue to - // modify it. Note that we do not use ActivityRecord#finishing here as finishing is not - // indicative of destruction (though destruction is indicative of finishing) as finishing - // can be delayed below. - if (r.isState(DESTROYING, DESTROYED)) { - return null; - } - r.setState(FINISHING, "finishCurrentActivityLocked"); final boolean finishingActivityInNonFocusedStack = r.getStack() != mStackSupervisor.getFocusedStack() @@ -4037,26 +4032,16 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai * state to destroy so only the cleanup here is needed. * * Note: Call before #removeActivityFromHistoryLocked. - * - * @param r The {@link ActivityRecord} to cleanup. - * @param cleanServices Whether services bound to the {@link ActivityRecord} should also be - * cleaned up. - * @param destroy Whether the {@link ActivityRecord} should be destroyed. - * @param clearProcess Whether the client process should be cleared. */ - private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean destroy, - boolean clearProcess) { + private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) { onActivityRemovedFromStack(r); r.deferRelaunchUntilPaused = false; r.frozenBeforeDestroy = false; - if (destroy) { + if (setState) { if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + r + " (cleaning up)"); r.setState(DESTROYED, "cleanupActivityLocked"); - } - - if (clearProcess) { if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during cleanUp for activity " + r); r.app = null; } @@ -4271,7 +4256,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai + ", app=" + (r.app != null ? r.app.processName : "(null)")); if (r.isState(DESTROYING, DESTROYED)) { - if (DEBUG_STATES) Slog.v(TAG_STATES, "activity " + r + " already finishing." + if (DEBUG_STATES) Slog.v(TAG_STATES, "activity " + r + " already destroying." + "skipping request with reason:" + reason); return false; } @@ -4282,8 +4267,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai boolean removedFromHistory = false; - cleanUpActivityLocked(r, false /* cleanServices */, false /* destroy */, - false /*clearProcess*/); + cleanUpActivityLocked(r, false, false); final boolean hadApp = r.app != null; @@ -4380,6 +4364,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } } + /** + * This method is to only be called from the client via binder when the activity is destroyed + * AND finished. + */ final void activityDestroyedLocked(ActivityRecord record, String reason) { if (record != null) { mHandler.removeMessages(DESTROY_TIMEOUT_MSG, record); @@ -4389,8 +4377,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (isInStackLocked(record) != null) { if (record.isState(DESTROYING, DESTROYED)) { - cleanUpActivityLocked(record, true /* cleanServices */, false /* destroy */, - false /*clearProcess*/); + cleanUpActivityLocked(record, true, false); removeActivityFromHistoryLocked(record, reason); } } @@ -4499,8 +4486,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai r.icicle = null; } } - cleanUpActivityLocked(r, true /* cleanServices */, remove /* destroy */, - true /*clearProcess*/); + cleanUpActivityLocked(r, true, true); if (remove) { removeActivityFromHistoryLocked(r, "appDied"); } @@ -4511,11 +4497,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return hasVisibleActivities; } - private void updateTransitLocked(int transit, ActivityOptions options) { + private void updateTransitLocked(int transit, ActivityRecord starting, + ActivityOptions options) { if (options != null) { - ActivityRecord r = topRunningActivityLocked(); - if (r != null && !r.isState(RESUMED)) { - r.updateOptionsLocked(options); + if (starting != null && !starting.isState(RESUMED)) { + starting.updateOptionsLocked(options); } else { ActivityOptions.abort(options); } @@ -4552,8 +4538,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } } - final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options, - AppTimeTracker timeTracker, String reason) { + final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord starting, + boolean noAnimation, ActivityOptions options, AppTimeTracker timeTracker, + String reason) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); final ActivityStack topStack = getDisplay().getTopStack(); @@ -4565,7 +4552,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (noAnimation) { ActivityOptions.abort(options); } else { - updateTransitLocked(TRANSIT_TASK_TO_FRONT, options); + updateTransitLocked(TRANSIT_TASK_TO_FRONT, starting, options); } return; } @@ -4603,7 +4590,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } ActivityOptions.abort(options); } else { - updateTransitLocked(TRANSIT_TASK_TO_FRONT, options); + updateTransitLocked(TRANSIT_TASK_TO_FRONT, r, options); } // If a new task is moved to the front, then mark the existing top activity as supporting // picture-in-picture while paused only if the task would not be considered an oerlay on top diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 185897a93381..efc0d7d87e63 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2196,7 +2196,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } final ActivityRecord r = task.getTopActivity(); - currentStack.moveTaskToFrontLocked(task, false /* noAnimation */, options, + currentStack.moveTaskToFrontLocked(task, r, false /* noAnimation */, options, r == null ? null : r.appTimeTracker, reason); if (DEBUG_STACK) Slog.d(TAG_STACK, @@ -3375,7 +3375,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D stack.goToSleepIfPossible(false /* shuttingDown */); } else { stack.awakeFromSleepingLocked(); - if (isFocusedStack(stack) && !mKeyguardController.isKeyguardLocked()) { + if (isFocusedStack(stack) + && !mKeyguardController.isKeyguardShowing(display.mDisplayId)) { // If the keyguard is unlocked - resume immediately. // It is possible that the display will not be awake at the time we // process the keyguard going away, which can happen before the sleep token diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index bd53eac7fee7..267023569ce0 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -1815,8 +1815,9 @@ class ActivityStarter { // We only want to move to the front, if we aren't going to launch on a // different stack. If we launch on a different stack, we will put the // task on top there. - mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions, - mStartActivity.appTimeTracker, "bringingFoundTaskToFront"); + mTargetStack.moveTaskToFrontLocked(intentTask, mStartActivity, mNoAnimation, + mOptions, mStartActivity.appTimeTracker, + "bringingFoundTaskToFront"); mMovedToFront = true; } else if (launchStack.inSplitScreenWindowingMode()) { if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) { @@ -1830,7 +1831,7 @@ class ActivityStarter { // We choose to move task to front instead of launching it adjacent // when specific stack was requested explicitly and it appeared to be // adjacent stack, but FLAG_ACTIVITY_LAUNCH_ADJACENT was not set. - mTargetStack.moveTaskToFrontLocked(intentTask, + mTargetStack.moveTaskToFrontLocked(intentTask, mStartActivity, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "bringToFrontInsteadOfAdjacentLaunch"); } @@ -2059,7 +2060,7 @@ class ActivityStarter { final TaskRecord topTask = mTargetStack.topTask(); if (topTask != sourceTask && !mAvoidMoveToFront) { - mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions, + mTargetStack.moveTaskToFrontLocked(sourceTask, mStartActivity, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "sourceTaskToFront"); } else if (mDoResume) { mTargetStack.moveToFront("sourceStackToFront"); @@ -2125,7 +2126,7 @@ class ActivityStarter { && top.userId == mStartActivity.userId) { if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK)) { - mTargetStack.moveTaskToFrontLocked(mInTask, mNoAnimation, mOptions, + mTargetStack.moveTaskToFrontLocked(mInTask, mStartActivity, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront"); if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { // We don't need to start a new activity, and the client said not to do @@ -2138,7 +2139,7 @@ class ActivityStarter { } if (!mAddingToTask) { - mTargetStack.moveTaskToFrontLocked(mInTask, mNoAnimation, mOptions, + mTargetStack.moveTaskToFrontLocked(mInTask, mStartActivity, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront"); // We don't actually want to have this activity added to the task, so just // stop here but still tell the caller that we consumed the intent. @@ -2158,8 +2159,8 @@ class ActivityStarter { updateBounds(mInTask, mLaunchParams.mBounds); } - mTargetStack.moveTaskToFrontLocked( - mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront"); + mTargetStack.moveTaskToFrontLocked(mInTask, mStartActivity, mNoAnimation, mOptions, + mStartActivity.appTimeTracker, "inTaskToFront"); addOrReparentStartingActivity(mInTask, "setTaskFromInTask"); if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 4541acde14b4..3db1da59b4ea 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -103,7 +103,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub .replaceWith("?"); private ByteBuffer mUtf8BufferStat = ByteBuffer.allocateDirect(MAX_LOW_POWER_STATS_SIZE); private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE); - private static final int MAX_LOW_POWER_STATS_SIZE = 512; + private static final int MAX_LOW_POWER_STATS_SIZE = 2048; /** * Replaces the information in the given rpmStats with up-to-date information. diff --git a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java index d7d18a99b66f..690d985ef096 100644 --- a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java @@ -43,6 +43,7 @@ class GlobalSettingsToPropertiesMapper { {Settings.Global.FPS_DEVISOR, ThreadedRenderer.DEBUG_FPS_DIVISOR}, {Settings.Global.DISPLAY_PANEL_LPM, "sys.display_panel_lpm"}, {Settings.Global.SYS_UIDCPUPOWER, "sys.uidcpupower"}, + {Settings.Global.SYS_TRACED, "persist.traced.enable"}, }; diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java index af99111e4bfa..ed39329844ef 100644 --- a/services/core/java/com/android/server/am/LockTaskController.java +++ b/services/core/java/com/android/server/am/LockTaskController.java @@ -469,6 +469,7 @@ public class LockTaskController { if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) { getStatusBarService().showPinningEnterExitToast(false /* entering */); } + mWindowManager.onLockTaskStateChanged(LOCK_TASK_MODE_NONE); } catch (RemoteException ex) { throw new RuntimeException(ex); } finally { @@ -580,6 +581,7 @@ public class LockTaskController { if (lockTaskModeState == LOCK_TASK_MODE_PINNED) { getStatusBarService().showPinningEnterExitToast(true /* entering */); } + mWindowManager.onLockTaskStateChanged(lockTaskModeState); mLockTaskModeState = lockTaskModeState; setStatusBarState(lockTaskModeState, userId); setKeyguardState(lockTaskModeState, userId); diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java index f1b3dfa5c003..3f05ecee77ef 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -1238,20 +1238,16 @@ class RecentTasks { * list (if any). */ private int findRemoveIndexForAddTask(TaskRecord task) { - int recentsCount = mTasks.size(); + final int recentsCount = mTasks.size(); + final int taskActivityType = task.getActivityType(); final Intent intent = task.intent; final boolean document = intent != null && intent.isDocument(); int maxRecents = task.maxRecents - 1; - final ActivityStack stack = task.getStack(); for (int i = 0; i < recentsCount; i++) { final TaskRecord tr = mTasks.get(i); - final ActivityStack trStack = tr.getStack(); - + final int trActivityType = tr.getActivityType(); if (task != tr) { - if (stack != null && trStack != null && stack != trStack) { - continue; - } - if (task.userId != tr.userId) { + if (taskActivityType != trActivityType || task.userId != tr.userId) { continue; } final Intent trIntent = tr.intent; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index f577d09cdb9f..9ef84d20004f 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -727,6 +727,36 @@ public class AudioService extends IAudioService.Stub } } + int maxAlarmVolume = SystemProperties.getInt("ro.config.alarm_vol_steps", -1); + if (maxAlarmVolume != -1) { + MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM] = maxAlarmVolume; + } + + int defaultAlarmVolume = SystemProperties.getInt("ro.config.alarm_vol_default", -1); + if (defaultAlarmVolume != -1 && + defaultAlarmVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]) { + AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_ALARM] = defaultAlarmVolume; + } else { + // Default is 6 out of 7 (default maximum), so scale accordingly. + AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_ALARM] = + 6 * MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM] / 7; + } + + int maxSystemVolume = SystemProperties.getInt("ro.config.system_vol_steps", -1); + if (maxSystemVolume != -1) { + MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = maxSystemVolume; + } + + int defaultSystemVolume = SystemProperties.getInt("ro.config.system_vol_default", -1); + if (defaultSystemVolume != -1 && + defaultSystemVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM]) { + AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = defaultSystemVolume; + } else { + // Default is to use maximum. + AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = + MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM]; + } + sSoundEffectVolumeDb = context.getResources().getInteger( com.android.internal.R.integer.config_soundEffectVolumeDb); diff --git a/services/core/java/com/android/server/backup/BackupUtils.java b/services/core/java/com/android/server/backup/BackupUtils.java index e5d564dec459..d817534551f7 100644 --- a/services/core/java/com/android/server/backup/BackupUtils.java +++ b/services/core/java/com/android/server/backup/BackupUtils.java @@ -18,9 +18,12 @@ package com.android.server.backup; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.util.Slog; +import com.android.internal.util.ArrayUtils; + import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; @@ -30,13 +33,13 @@ import java.util.List; public class BackupUtils { private static final String TAG = "BackupUtils"; - private static final boolean DEBUG = false; // STOPSHIP if true + private static final boolean DEBUG = false; - public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) { - if (target == null) { + public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target, + PackageManagerInternal pmi) { + if (target == null || target.packageName == null) { return false; } - // If the target resides on the system partition, we allow it to restore // data from the like-named package in a restore set even if the signatures // do not match. (Unlike general applications, those flashed to the system @@ -47,48 +50,53 @@ public class BackupUtils { return true; } - // Allow unsigned apps, but not signed on one device and unsigned on the other - // !!! TODO: is this the right policy? - Signature[] deviceSigs = target.signatures; - if (DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes - + " device=" + deviceSigs); - if ((storedSigHashes == null || storedSigHashes.size() == 0) - && (deviceSigs == null || deviceSigs.length == 0)) { - return true; - } - if (storedSigHashes == null || deviceSigs == null) { + // Don't allow unsigned apps on either end + if (ArrayUtils.isEmpty(storedSigHashes)) { return false; } - // !!! TODO: this demands that every stored signature match one - // that is present on device, and does not demand the converse. - // Is this this right policy? - final int nStored = storedSigHashes.size(); - final int nDevice = deviceSigs.length; + Signature[][] deviceHistorySigs = target.signingCertificateHistory; + if (ArrayUtils.isEmpty(deviceHistorySigs)) { + Slog.w(TAG, "signingCertificateHistory is empty, app was either unsigned or the flag" + + " PackageManager#GET_SIGNING_CERTIFICATES was not specified"); + return false; + } - // hash each on-device signature - ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice); - for (int i = 0; i < nDevice; i++) { - deviceHashes.add(hashSignature(deviceSigs[i])); + if (DEBUG) { + Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes + + " device=" + deviceHistorySigs); } - // now ensure that each stored sig (hash) matches an on-device sig (hash) - for (int n = 0; n < nStored; n++) { - boolean match = false; - final byte[] storedHash = storedSigHashes.get(n); - for (int i = 0; i < nDevice; i++) { - if (Arrays.equals(storedHash, deviceHashes.get(i))) { - match = true; - break; + final int nStored = storedSigHashes.size(); + if (nStored == 1) { + // if the app is only signed with one sig, it's possible it has rotated its key + // the checks with signing history are delegated to PackageManager + // TODO(b/73988180): address the case that app has declared restoreAnyVersion and is + // restoring from higher version to lower after having rotated the key (i.e. higher + // version has different sig than lower version that we want to restore to) + return pmi.isDataRestoreSafe(storedSigHashes.get(0), target.packageName); + } else { + // the app couldn't have rotated keys, since it was signed with multiple sigs - do + // a check to see if we find a match for all stored sigs + // since app hasn't rotated key, we only need to check with deviceHistorySigs[0] + ArrayList<byte[]> deviceHashes = hashSignatureArray(deviceHistorySigs[0]); + int nDevice = deviceHashes.size(); + // ensure that each stored sig matches an on-device sig + for (int i = 0; i < nStored; i++) { + boolean match = false; + for (int j = 0; j < nDevice; j++) { + if (Arrays.equals(storedSigHashes.get(i), deviceHashes.get(j))) { + match = true; + break; + } + } + if (!match) { + return false; } } - // match is false when no on-device sig matched one of the stored ones - if (!match) { - return false; - } + // we have found a match for all stored sigs + return true; } - - return true; } public static byte[] hashSignature(byte[] signature) { diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java index f1a806bb4074..4f31e533f8f9 100644 --- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java +++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java @@ -102,9 +102,12 @@ public class NetdEventListenerService extends INetdEventListener.Stub { /** - * There are only 2 possible callbacks. + * There are only 3 possible callbacks. * - * mNetdEventCallbackList[CALLBACK_CALLER_DEVICE_POLICY]. + * mNetdEventCallbackList[CALLBACK_CALLER_CONNECTIVITY_SERVICE] + * Callback registered/unregistered by ConnectivityService. + * + * mNetdEventCallbackList[CALLBACK_CALLER_DEVICE_POLICY] * Callback registered/unregistered when logging is being enabled/disabled in DPM * by the device owner. It's DevicePolicyManager's responsibility to ensure that. * @@ -113,6 +116,7 @@ public class NetdEventListenerService extends INetdEventListener.Stub { */ @GuardedBy("this") private static final int[] ALLOWED_CALLBACK_TYPES = { + INetdEventCallback.CALLBACK_CALLER_CONNECTIVITY_SERVICE, INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY, INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST }; @@ -212,6 +216,19 @@ public class NetdEventListenerService extends INetdEventListener.Stub { @Override // Called concurrently by multiple binder threads. // This method must not block or perform long-running operations. + public synchronized void onPrivateDnsValidationEvent(int netId, + String ipAddress, String hostname, boolean validated) + throws RemoteException { + for (INetdEventCallback callback : mNetdEventCallbackList) { + if (callback != null) { + callback.onPrivateDnsValidationEvent(netId, ipAddress, hostname, validated); + } + } + } + + @Override + // Called concurrently by multiple binder threads. + // This method must not block or perform long-running operations. public synchronized void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid) throws RemoteException { long timestamp = System.currentTimeMillis(); diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index 3a8e291f7976..240592528565 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -45,7 +45,7 @@ abstract class DisplayDevice { private Rect mCurrentDisplayRect; // The display device owns its surface, but it should only set it - // within a transaction from performTraversalInTransactionLocked. + // within a transaction from performTraversalLocked. private Surface mCurrentSurface; // DEBUG STATE: Last device info which was written to the log, or null if none. @@ -122,7 +122,7 @@ abstract class DisplayDevice { /** * Gives the display device a chance to update its properties while in a transaction. */ - public void performTraversalInTransactionLocked() { + public void performTraversalLocked(SurfaceControl.Transaction t) { } /** @@ -140,7 +140,7 @@ abstract class DisplayDevice { /** * Sets the mode, if supported. */ - public void requestDisplayModesInTransactionLocked(int colorMode, int modeId) { + public void requestDisplayModesLocked(int colorMode, int modeId) { } public void onOverlayChangedLocked() { @@ -149,10 +149,10 @@ abstract class DisplayDevice { /** * Sets the display layer stack while in a transaction. */ - public final void setLayerStackInTransactionLocked(int layerStack) { + public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack) { if (mCurrentLayerStack != layerStack) { mCurrentLayerStack = layerStack; - SurfaceControl.setDisplayLayerStack(mDisplayToken, layerStack); + t.setDisplayLayerStack(mDisplayToken, layerStack); } } @@ -166,7 +166,7 @@ abstract class DisplayDevice { * mapped to. displayRect is specified post-orientation, that is * it uses the orientation seen by the end-user */ - public final void setProjectionInTransactionLocked(int orientation, + public final void setProjectionLocked(SurfaceControl.Transaction t, int orientation, Rect layerStackRect, Rect displayRect) { if (mCurrentOrientation != orientation || mCurrentLayerStackRect == null @@ -185,7 +185,7 @@ abstract class DisplayDevice { } mCurrentDisplayRect.set(displayRect); - SurfaceControl.setDisplayProjection(mDisplayToken, + t.setDisplayProjection(mDisplayToken, orientation, layerStackRect, displayRect); } } @@ -193,10 +193,10 @@ abstract class DisplayDevice { /** * Sets the display surface while in a transaction. */ - public final void setSurfaceInTransactionLocked(Surface surface) { + public final void setSurfaceLocked(SurfaceControl.Transaction t, Surface surface) { if (mCurrentSurface != surface) { mCurrentSurface = surface; - SurfaceControl.setDisplaySurface(mDisplayToken, surface); + t.setDisplaySurface(mDisplayToken, surface); } } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index a5c1fe299e4e..9861ea735570 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -74,6 +74,7 @@ import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; +import android.view.SurfaceControl; import com.android.internal.util.Preconditions; import com.android.server.AnimationThread; @@ -457,14 +458,14 @@ public final class DisplayManagerService extends SystemService { } @VisibleForTesting - void performTraversalInTransactionFromWindowManagerInternal() { + void performTraversalInternal(SurfaceControl.Transaction t) { synchronized (mSyncRoot) { if (!mPendingTraversal) { return; } mPendingTraversal = false; - performTraversalInTransactionLocked(); + performTraversalLocked(t); } // List is self-synchronized copy-on-write. @@ -1056,7 +1057,7 @@ public final class DisplayManagerService extends SystemService { return changed; } - private void performTraversalInTransactionLocked() { + private void performTraversalLocked(SurfaceControl.Transaction t) { // Clear all viewports before configuring displays so that we can keep // track of which ones we have configured. clearViewportsLocked(); @@ -1065,8 +1066,8 @@ public final class DisplayManagerService extends SystemService { final int count = mDisplayDevices.size(); for (int i = 0; i < count; i++) { DisplayDevice device = mDisplayDevices.get(i); - configureDisplayInTransactionLocked(device); - device.performTraversalInTransactionLocked(); + configureDisplayLocked(t, device); + device.performTraversalLocked(t); } // Tell the input system about these new viewports. @@ -1150,7 +1151,7 @@ public final class DisplayManagerService extends SystemService { mVirtualTouchViewports.clear(); } - private void configureDisplayInTransactionLocked(DisplayDevice device) { + private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) { final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0; @@ -1175,7 +1176,7 @@ public final class DisplayManagerService extends SystemService { + device.getDisplayDeviceInfoLocked()); return; } - display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF); + display.configureDisplayLocked(t, device, info.state == Display.STATE_OFF); // Update the viewports if needed. if (!mDefaultViewport.valid @@ -1233,7 +1234,7 @@ public final class DisplayManagerService extends SystemService { mHandler.sendMessage(msg); } - // Requests that performTraversalsInTransactionFromWindowManager be called at a + // Requests that performTraversals be called at a // later time to apply changes to surfaces and displays. private void scheduleTraversalLocked(boolean inTraversal) { if (!mPendingTraversal && mWindowManagerInternal != null) { @@ -2031,8 +2032,8 @@ public final class DisplayManagerService extends SystemService { } @Override - public void performTraversalInTransactionFromWindowManager() { - performTraversalInTransactionFromWindowManagerInternal(); + public void performTraversal(SurfaceControl.Transaction t) { + performTraversalInternal(t); } @Override diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 0d8ec6d23089..5ca9abc8355d 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -584,10 +584,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { } @Override - public void requestDisplayModesInTransactionLocked( - int colorMode, int modeId) { - if (requestModeInTransactionLocked(modeId) || - requestColorModeInTransactionLocked(colorMode)) { + public void requestDisplayModesLocked(int colorMode, int modeId) { + if (requestModeLocked(modeId) || + requestColorModeLocked(colorMode)) { updateDeviceInfoLocked(); } } @@ -597,7 +596,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { updateDeviceInfoLocked(); } - public boolean requestModeInTransactionLocked(int modeId) { + public boolean requestModeLocked(int modeId) { if (modeId == 0) { modeId = mDefaultModeId; } else if (mSupportedModes.indexOfKey(modeId) < 0) { @@ -623,7 +622,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { return true; } - public boolean requestColorModeInTransactionLocked(int colorMode) { + public boolean requestColorModeLocked(int colorMode) { if (mActiveColorMode == colorMode) { return false; } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index e582fdf63472..23ee56b24b19 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -21,6 +21,7 @@ import android.hardware.display.DisplayManagerInternal; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; +import android.view.SurfaceControl; import java.io.PrintWriter; import java.util.Arrays; @@ -304,17 +305,18 @@ final class LogicalDisplay { * @param device The display device to modify. * @param isBlanked True if the device is being blanked. */ - public void configureDisplayInTransactionLocked(DisplayDevice device, + public void configureDisplayLocked(SurfaceControl.Transaction t, + DisplayDevice device, boolean isBlanked) { // Set the layer stack. - device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack); + device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack); // Set the color mode and mode. if (device == mPrimaryDisplayDevice) { - device.requestDisplayModesInTransactionLocked( + device.requestDisplayModesLocked( mRequestedColorMode, mRequestedModeId); } else { - device.requestDisplayModesInTransactionLocked(0, 0); // Revert to default. + device.requestDisplayModesLocked(0, 0); // Revert to default. } // Only grab the display info now as it may have been changed based on the requests above. @@ -377,7 +379,7 @@ final class LogicalDisplay { mTempDisplayRect.right += mDisplayOffsetX; mTempDisplayRect.top += mDisplayOffsetY; mTempDisplayRect.bottom += mDisplayOffsetY; - device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect); + device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect); } /** diff --git a/services/core/java/com/android/server/display/OWNERS b/services/core/java/com/android/server/display/OWNERS index 83614219a3b5..98e32997e587 100644 --- a/services/core/java/com/android/server/display/OWNERS +++ b/services/core/java/com/android/server/display/OWNERS @@ -1,3 +1,5 @@ michaelwr@google.com +hackbod@google.com +ogunwale@google.com -per-file ColorDisplayService.java=christyfranks@google.com
\ No newline at end of file +per-file ColorDisplayService.java=christyfranks@google.com diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java index 27327d4eb100..e65637f04975 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java @@ -271,12 +271,12 @@ final class OverlayDisplayAdapter extends DisplayAdapter { } @Override - public void performTraversalInTransactionLocked() { + public void performTraversalLocked(SurfaceControl.Transaction t) { if (mSurfaceTexture != null) { if (mSurface == null) { mSurface = new Surface(mSurfaceTexture); } - setSurfaceInTransactionLocked(mSurface); + setSurfaceLocked(t, mSurface); } } @@ -315,7 +315,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { } @Override - public void requestDisplayModesInTransactionLocked(int color, int id) { + public void requestDisplayModesLocked(int color, int id) { int index = -1; if (id == 0) { // Use the default. diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index f86d57634bff..6111c23f252c 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -269,12 +269,12 @@ public class VirtualDisplayAdapter extends DisplayAdapter { } @Override - public void performTraversalInTransactionLocked() { + public void performTraversalLocked(SurfaceControl.Transaction t) { if ((mPendingChanges & PENDING_RESIZE) != 0) { - SurfaceControl.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight); + t.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight); } if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) { - setSurfaceInTransactionLocked(mSurface); + setSurfaceLocked(t, mSurface); } mPendingChanges = 0; } diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java index 329337933956..e8d6ad455fbf 100644 --- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java @@ -620,9 +620,9 @@ final class WifiDisplayAdapter extends DisplayAdapter { } @Override - public void performTraversalInTransactionLocked() { + public void performTraversalLocked(SurfaceControl.Transaction t) { if (mSurface != null) { - setSurfaceInTransactionLocked(mSurface); + setSurfaceLocked(t, mSurface); } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index 8efce8602e78..5bfdf41a6654 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -45,6 +45,7 @@ import java.security.PublicKey; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.cert.CertPath; +import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -148,6 +149,11 @@ public class KeySyncTask implements Runnable { mPlatformKeyManager.invalidatePlatformKey(mUserId, generation); return; } + if (isCustomLockScreen()) { + Log.w(TAG, "Unsupported credential type " + mCredentialType + "for user " + mUserId); + mRecoverableKeyStoreDb.invalidateKeysForUserIdOnCustomScreenLock(mUserId); + return; + } List<Integer> recoveryAgents = mRecoverableKeyStoreDb.getRecoveryAgents(mUserId); for (int uid : recoveryAgents) { @@ -158,6 +164,12 @@ public class KeySyncTask implements Runnable { } } + private boolean isCustomLockScreen() { + return mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE + && mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_PATTERN + && mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; + } + private void syncKeysForAgent(int recoveryAgentUid) { boolean recreateCurrentVersion = false; if (!shoudCreateSnapshot(recoveryAgentUid)) { @@ -284,17 +296,23 @@ public class KeySyncTask implements Runnable { // If application keys are not updated, snapshot will not be created on next unlock. mRecoverableKeyStoreDb.setShouldCreateSnapshot(mUserId, recoveryAgentUid, false); - mRecoverySnapshotStorage.put(recoveryAgentUid, new KeyChainSnapshot.Builder() + KeyChainSnapshot.Builder keyChainSnapshotBuilder = new KeyChainSnapshot.Builder() .setSnapshotVersion(getSnapshotVersion(recoveryAgentUid, recreateCurrentVersion)) .setMaxAttempts(TRUSTED_HARDWARE_MAX_ATTEMPTS) .setCounterId(counterId) .setTrustedHardwarePublicKey(SecureBox.encodePublicKey(publicKey)) - .setTrustedHardwareCertPath(certPath) .setServerParams(vaultHandle) .setKeyChainProtectionParams(metadataList) .setWrappedApplicationKeys(createApplicationKeyEntries(encryptedApplicationKeys)) - .setEncryptedRecoveryKeyBlob(encryptedRecoveryKey) - .build()); + .setEncryptedRecoveryKeyBlob(encryptedRecoveryKey); + try { + keyChainSnapshotBuilder.setTrustedHardwareCertPath(certPath); + } catch(CertificateException e) { + // Should not happen, as it's just deserialized from bytes stored in the db + Log.wtf(TAG, "Cannot serialize CertPath when calling setTrustedHardwareCertPath", e); + return; + } + mRecoverySnapshotStorage.put(recoveryAgentUid, keyChainSnapshotBuilder.build()); mSnapshotListenersStorage.recoverySnapshotAvailable(recoveryAgentUid); } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java index 89ddb6c9eb30..2676ee8897af 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java @@ -320,6 +320,20 @@ public class RecoverableKeyStoreDb { } /** + * Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}. + */ + public void invalidateKeysForUserIdOnCustomScreenLock(int userId) { + SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase(); + ContentValues values = new ContentValues(); + values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, + RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE); + String selection = + KeysEntry.COLUMN_NAME_USER_ID + " = ?"; + db.update(KeysEntry.TABLE_NAME, values, selection, + new String[] {String.valueOf(userId)}); + } + + /** * Returns the generation ID associated with the platform key of the user with {@code userId}. */ public int getPlatformKeyGenerationId(int userId) { diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS index 755c1d6f8aff..8adea0e85d12 100644 --- a/services/core/java/com/android/server/media/OWNERS +++ b/services/core/java/com/android/server/media/OWNERS @@ -1,3 +1,4 @@ lajos@google.com elaurent@google.com sungsoo@google.com +jaewan@google.com diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index aa1f7d95845f..e86253037b08 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -874,7 +874,14 @@ public class ZenModeHelper { } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA) { applyRestrictions(muteMedia || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_SYSTEM) { - applyRestrictions(muteSystem || muteEverything, usage); + if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) { + // normally DND will only restrict touch sounds, not haptic feedback/vibrations + applyRestrictions(muteSystem || muteEverything, usage, + AppOpsManager.OP_PLAY_AUDIO); + applyRestrictions(false, usage, AppOpsManager.OP_VIBRATE); + } else { + applyRestrictions(muteSystem || muteEverything, usage); + } } else { applyRestrictions(muteEverything, usage); } @@ -883,18 +890,31 @@ public class ZenModeHelper { @VisibleForTesting - protected void applyRestrictions(boolean mute, int usage) { + protected void applyRestrictions(boolean mute, int usage, int code) { final String[] exceptionPackages = null; // none (for now) - mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage, - mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, - exceptionPackages); - mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, usage, - mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, - exceptionPackages); + // Only do this if we are executing within the system process... otherwise + // we are running as test code, so don't have access to the protected call. + if (Process.myUid() == Process.SYSTEM_UID) { + final long ident = Binder.clearCallingIdentity(); + try { + mAppOps.setRestriction(code, usage, + mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, + exceptionPackages); + } finally { + Binder.restoreCallingIdentity(ident); + } + } } @VisibleForTesting + protected void applyRestrictions(boolean mute, int usage) { + applyRestrictions(mute, usage, AppOpsManager.OP_VIBRATE); + applyRestrictions(mute, usage, AppOpsManager.OP_PLAY_AUDIO); + } + + + @VisibleForTesting protected void applyZenToRingerMode() { if (mAudioManager == null) return; // force the ringer mode into compliance @@ -1183,15 +1203,21 @@ public class ZenModeHelper { final Bundle extras = new Bundle(); extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, mContext.getResources().getString(R.string.global_action_settings)); - return new Notification.Builder(mContext, SystemNotificationChannels.SYSTEM_CHANGES) + int title = R.string.zen_upgrade_notification_title; + int content = R.string.zen_upgrade_notification_content; + if (NotificationManager.Policy.areAllVisualEffectsSuppressed( + getNotificationPolicy().suppressedVisualEffects)) { + title = R.string.zen_upgrade_notification_visd_title; + content = R.string.zen_upgrade_notification_visd_content; + } + return new Notification.Builder(mContext, SystemNotificationChannels.DO_NOT_DISTURB) .setSmallIcon(R.drawable.ic_settings_24dp) - .setContentTitle(mContext.getResources().getString( - R.string.zen_upgrade_notification_title)) - .setContentText(mContext.getResources().getString( - R.string.zen_upgrade_notification_content)) + .setContentTitle(mContext.getResources().getString(title)) + .setContentText(mContext.getResources().getString(content)) .setAutoCancel(true) .setLocalOnly(true) .addExtras(extras) + .setStyle(new Notification.BigTextStyle()) .setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0, null)) .build(); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 707184fcfb97..5430d44504a0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -176,6 +176,7 @@ import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.ParseFlags; import android.content.pm.PackageParser.ServiceIntentInfo; +import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.PackageStats; import android.content.pm.PackageUserState; @@ -2877,7 +2878,8 @@ public class PackageManagerService extends IPackageManager.Stub rescanFlags = scanFlags | SCAN_AS_SYSTEM; - } else if (FileUtils.contains(privilegedVendorAppDir, scanFile)) { + } else if (FileUtils.contains(privilegedVendorAppDir, scanFile) + || FileUtils.contains(privilegedOdmAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; @@ -2886,7 +2888,8 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_SYSTEM | SCAN_AS_VENDOR | SCAN_AS_PRIVILEGED; - } else if (FileUtils.contains(vendorAppDir, scanFile)) { + } else if (FileUtils.contains(vendorAppDir, scanFile) + || FileUtils.contains(odmAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; @@ -11788,6 +11791,8 @@ public class PackageManagerService extends IPackageManager.Stub codeRoot = Environment.getOemDirectory(); } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) { codeRoot = Environment.getVendorDirectory(); + } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) { + codeRoot = Environment.getOdmDirectory(); } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) { codeRoot = Environment.getProductDirectory(); } else { @@ -18217,9 +18222,11 @@ public class PackageManagerService extends IPackageManager.Stub try { final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app"); + final File privilegedOdmAppDir = new File(Environment.getOdmDirectory(), "priv-app"); final File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app"); return path.startsWith(privilegedAppDir.getCanonicalPath()) || path.startsWith(privilegedVendorAppDir.getCanonicalPath()) + || path.startsWith(privilegedOdmAppDir.getCanonicalPath()) || path.startsWith(privilegedProductAppDir.getCanonicalPath()); } catch (IOException e) { Slog.e(TAG, "Unable to access code path " + path); @@ -18238,7 +18245,8 @@ public class PackageManagerService extends IPackageManager.Stub static boolean locationIsVendor(String path) { try { - return path.startsWith(Environment.getVendorDirectory().getCanonicalPath()); + return path.startsWith(Environment.getVendorDirectory().getCanonicalPath()) + || path.startsWith(Environment.getOdmDirectory().getCanonicalPath()); } catch (IOException e) { Slog.e(TAG, "Unable to access code path " + path); } @@ -23376,6 +23384,36 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } @Override + public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) { + SigningDetails sd = getSigningDetails(packageName); + if (sd == null) { + return false; + } + return sd.hasSha256Certificate(restoringFromSigHash, + SigningDetails.CertCapabilities.INSTALLED_DATA); + } + + @Override + public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) { + SigningDetails sd = getSigningDetails(packageName); + if (sd == null) { + return false; + } + return sd.hasCertificate(restoringFromSig, + SigningDetails.CertCapabilities.INSTALLED_DATA); + } + + private SigningDetails getSigningDetails(@NonNull String packageName) { + synchronized (mPackages) { + PackageParser.Package p = mPackages.get(packageName); + if (p == null) { + return null; + } + return p.mSigningDetails; + } + } + + @Override public int getPermissionFlagsTEMP(String permName, String packageName, int userId) { return PackageManagerService.this.getPermissionFlags(permName, packageName, userId); } @@ -23840,6 +23878,15 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } @Override + public boolean canAccessComponent(int callingUid, ComponentName component, int userId) { + synchronized (mPackages) { + final PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + return !PackageManagerService.this.filterAppAccessLPr( + ps, callingUid, component, TYPE_UNKNOWN, userId); + } + } + + @Override public boolean hasInstantApplicationMetadata(String packageName, int userId) { synchronized (mPackages) { return mInstantAppRegistry.hasInstantApplicationMetadataLPr(packageName, userId); diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java index 520ed2526b17..eeaa3330dee4 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java +++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java @@ -18,10 +18,13 @@ package com.android.server.pm; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.pm.PackageInfo; +import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutInfo; +import android.content.pm.Signature; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; import com.android.server.backup.BackupUtils; import libcore.util.HexEncoding; @@ -137,7 +140,8 @@ class ShortcutPackageInfo { //@DisabledReason public int canRestoreTo(ShortcutService s, PackageInfo currentPackage, boolean anyVersionOkay) { - if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage)) { + PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); + if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage, pmi)) { Slog.w(TAG, "Can't restore: Package signature mismatch"); return ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH; } @@ -159,13 +163,15 @@ class ShortcutPackageInfo { public static ShortcutPackageInfo generateForInstalledPackageForTest( ShortcutService s, String packageName, @UserIdInt int packageUserId) { final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId); - if (pi.signatures == null || pi.signatures.length == 0) { + // retrieve the newest sigs + Signature[][] signingHistory = pi.signingCertificateHistory; + if (signingHistory == null || signingHistory.length == 0) { Slog.e(TAG, "Can't get signatures: package=" + packageName); return null; } + Signature[] signatures = signingHistory[signingHistory.length - 1]; final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.getLongVersionCode(), - pi.lastUpdateTime, BackupUtils.hashSignatureArray(pi.signatures), - /* shadow=*/ false); + pi.lastUpdateTime, BackupUtils.hashSignatureArray(signatures), /* shadow=*/ false); ret.mBackupSourceBackupAllowed = s.shouldBackupApp(pi); ret.mBackupSourceVersionCode = pi.getLongVersionCode(); @@ -185,7 +191,15 @@ class ShortcutPackageInfo { Slog.w(TAG, "Package not found: " + pkg.getPackageName()); return; } - mSigHashes = BackupUtils.hashSignatureArray(pi.signatures); + // retrieve the newest sigs + Signature[][] signingHistory = pi.signingCertificateHistory; + if (signingHistory == null || signingHistory.length == 0) { + Slog.w(TAG, "Not refreshing signature for " + pkg.getPackageName() + + " since it appears to have no signature history."); + return; + } + Signature[] signatures = signingHistory[signingHistory.length - 1]; + mSigHashes = BackupUtils.hashSignatureArray(signatures); } public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup) @@ -221,7 +235,6 @@ class ShortcutPackageInfo { public void loadFromXml(XmlPullParser parser, boolean fromBackup) throws IOException, XmlPullParserException { - // Don't use the version code from the backup file. final long versionCode = ShortcutService.parseLongAttribute(parser, ATTR_VERSION, ShortcutInfo.VERSION_CODE_UNKNOWN); diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 265cc8ebe4d3..15b461729495 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -3121,7 +3121,8 @@ public class ShortcutService extends IShortcutService.Stub { try { return mIPackageManager.getPackageInfo( packageName, PACKAGE_MATCH_FLAGS - | (getSignatures ? PackageManager.GET_SIGNATURES : 0), userId); + | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0), + userId); } catch (RemoteException e) { // Shouldn't happen. Slog.wtf(TAG, "RemoteException", e); diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 4abcce16f777..bf85f30d092e 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -1240,6 +1240,10 @@ public final class DefaultPermissionGrantPolicy { if (dir.isDirectory() && dir.canRead()) { Collections.addAll(ret, dir.listFiles()); } + dir = new File(Environment.getOdmDirectory(), "etc/default-permissions"); + if (dir.isDirectory() && dir.canRead()) { + Collections.addAll(ret, dir.listFiles()); + } dir = new File(Environment.getProductDirectory(), "etc/default-permissions"); if (dir.isDirectory() && dir.canRead()) { Collections.addAll(ret, dir.listFiles()); diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java index c6ec287d9c6a..4aa24465215b 100644 --- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java +++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java @@ -16,6 +16,9 @@ package com.android.server.policy; +import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; +import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; + import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.app.ActivityManager; @@ -78,6 +81,7 @@ public class ImmersiveModeConfirmation { // Local copy of vr mode enabled state, to avoid calling into VrManager with // the lock held. boolean mVrModeEnabled = false; + private int mLockTaskState = LOCK_TASK_MODE_NONE; public ImmersiveModeConfirmation(Context context) { mContext = ActivityThread.currentActivityThread().getSystemUiContext(); @@ -148,7 +152,8 @@ public class ImmersiveModeConfirmation { && userSetupComplete && !mVrModeEnabled && !navBarEmpty - && !UserManager.isDeviceInDemoMode(mContext)) { + && !UserManager.isDeviceInDemoMode(mContext) + && (mLockTaskState != LOCK_TASK_MODE_LOCKED)) { mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs); } } else { @@ -401,4 +406,8 @@ public class ImmersiveModeConfirmation { } } }; + + void onLockTaskModeChangedLw(int lockTaskState) { + mLockTaskState = lockTaskState; + } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 2d4438debf7d..3cd79e1642dc 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -1456,6 +1456,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { + "already in the process of turning the screen on."); return; } + Slog.d(TAG, "powerPress: eventTime=" + eventTime + " interactive=" + interactive + + " count=" + count + " beganFromNonInteractive=" + mBeganFromNonInteractive + + " mShortPressOnPowerBehavior=" + mShortPressOnPowerBehavior); if (count == 2) { powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior); @@ -1755,7 +1758,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } void showGlobalActionsInternal() { - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); } @@ -8809,4 +8811,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { return Integer.toString(behavior); } } + + @Override + public void onLockTaskStateChangedLw(int lockTaskState) { + mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState); + } } diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 8ec8c5b3c77e..b0d5e1a8c62a 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -66,6 +66,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.Manifest; import android.annotation.IntDef; import android.annotation.Nullable; +import android.app.ActivityManager; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.CompatibilityInfo; @@ -1731,4 +1732,15 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * on the next user activity. */ public void requestUserActivityNotification(); + + /** + * Called when the state of lock task mode changes. This should be used to disable immersive + * mode confirmation. + * + * @param lockTaskState the new lock task mode state. One of + * {@link ActivityManager#LOCK_TASK_MODE_NONE}, + * {@link ActivityManager#LOCK_TASK_MODE_LOCKED}, + * {@link ActivityManager#LOCK_TASK_MODE_PINNED}. + */ + void onLockTaskStateChangedLw(int lockTaskState); } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index b729b6a0f47f..285532aef71f 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -720,9 +720,12 @@ final class Notifier { private void playChargingStartedSound() { final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0; + final boolean dndOff = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) + == Settings.Global.ZEN_MODE_OFF; final String soundPath = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.CHARGING_STARTED_SOUND); - if (enabled && soundPath != null) { + if (enabled && dndOff && soundPath != null) { final Uri soundUri = Uri.parse("file://" + soundPath); if (soundUri != null) { final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); diff --git a/services/core/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java index 6bacdfdafbda..8af76a17f084 100644 --- a/services/core/java/com/android/server/search/Searchables.java +++ b/services/core/java/com/android/server/search/Searchables.java @@ -26,14 +26,18 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; +import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import com.android.server.LocalServices; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -119,7 +123,15 @@ public class Searchables { SearchableInfo result; synchronized (this) { result = mSearchablesMap.get(activity); - if (result != null) return result; + if (result != null) { + final PackageManagerInternal pm = + LocalServices.getService(PackageManagerInternal.class); + if (pm.canAccessComponent(Binder.getCallingUid(), result.getSearchActivity(), + UserHandle.getCallingUserId())) { + return result; + } + return null; + } } // Step 2. See if the current activity references a searchable. @@ -170,8 +182,16 @@ public class Searchables { result = mSearchablesMap.get(referredActivity); if (result != null) { mSearchablesMap.put(activity, result); + } + } + if (result != null) { + final PackageManagerInternal pm = + LocalServices.getService(PackageManagerInternal.class); + if (pm.canAccessComponent(Binder.getCallingUid(), result.getSearchActivity(), + UserHandle.getCallingUserId())) { return result; } + return null; } } @@ -410,7 +430,7 @@ public class Searchables { activities = mPm.queryIntentActivities(intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), - flags, mUserId).getList(); + flags | PackageManager.MATCH_INSTANT, mUserId).getList(); } catch (RemoteException re) { // Local call } @@ -421,36 +441,82 @@ public class Searchables { * Returns the list of searchable activities. */ public synchronized ArrayList<SearchableInfo> getSearchablesList() { - ArrayList<SearchableInfo> result = new ArrayList<SearchableInfo>(mSearchablesList); - return result; + return createFilterdSearchableInfoList(mSearchablesList); } /** * Returns a list of the searchable activities that can be included in global search. */ public synchronized ArrayList<SearchableInfo> getSearchablesInGlobalSearchList() { - return new ArrayList<SearchableInfo>(mSearchablesInGlobalSearchList); + return createFilterdSearchableInfoList(mSearchablesInGlobalSearchList); } /** * Returns a list of activities that handle the global search intent. */ public synchronized ArrayList<ResolveInfo> getGlobalSearchActivities() { - return new ArrayList<ResolveInfo>(mGlobalSearchActivities); + return createFilterdResolveInfoList(mGlobalSearchActivities); + } + + private ArrayList<SearchableInfo> createFilterdSearchableInfoList(List<SearchableInfo> list) { + if (list == null) { + return null; + } + final ArrayList<SearchableInfo> resultList = new ArrayList<>(list.size()); + final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getCallingUserId(); + for (SearchableInfo info : list) { + if (pm.canAccessComponent(callingUid, info.getSearchActivity(), callingUserId)) { + resultList.add(info); + } + } + return resultList; + } + + private ArrayList<ResolveInfo> createFilterdResolveInfoList(List<ResolveInfo> list) { + if (list == null) { + return null; + } + final ArrayList<ResolveInfo> resultList = new ArrayList<>(list.size()); + final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getCallingUserId(); + for (ResolveInfo info : list) { + if (pm.canAccessComponent( + callingUid, info.activityInfo.getComponentName(), callingUserId)) { + resultList.add(info); + } + } + return resultList; } /** * Gets the name of the global search activity. */ public synchronized ComponentName getGlobalSearchActivity() { - return mCurrentGlobalSearchActivity; + final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getCallingUserId(); + if (mCurrentGlobalSearchActivity != null + && pm.canAccessComponent(callingUid, mCurrentGlobalSearchActivity, callingUserId)) { + return mCurrentGlobalSearchActivity; + } + return null; } /** * Gets the name of the web search activity. */ public synchronized ComponentName getWebSearchActivity() { - return mWebSearchActivity; + final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getCallingUserId(); + if (mWebSearchActivity != null + && pm.canAccessComponent(callingUid, mWebSearchActivity, callingUserId)) { + return mWebSearchActivity; + } + return null; } void dump(FileDescriptor fd, PrintWriter pw, String[] args) { diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java index f9a4ea211f07..4e7fb969f398 100644 --- a/services/core/java/com/android/server/slice/PinnedSliceState.java +++ b/services/core/java/com/android/server/slice/PinnedSliceState.java @@ -14,9 +14,6 @@ package com.android.server.slice; -import static android.app.slice.SliceManager.PERMISSION_GRANTED; - -import android.app.slice.Slice; import android.app.slice.SliceProvider; import android.app.slice.SliceSpec; import android.content.ContentProviderClient; @@ -33,7 +30,6 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -54,18 +50,24 @@ public class PinnedSliceState { private final ArraySet<String> mPinnedPkgs = new ArraySet<>(); @GuardedBy("mLock") private final ArrayMap<IBinder, ListenerInfo> mListeners = new ArrayMap<>(); + private final String mPkg; @GuardedBy("mLock") private SliceSpec[] mSupportedSpecs = null; private final DeathRecipient mDeathRecipient = this::handleRecheckListeners; private boolean mSlicePinned; - public PinnedSliceState(SliceManagerService service, Uri uri) { + public PinnedSliceState(SliceManagerService service, Uri uri, String pkg) { mService = service; mUri = uri; + mPkg = pkg; mLock = mService.getLock(); } + public String getPkg() { + return mPkg; + } + public SliceSpec[] getSpecs() { return mSupportedSpecs; } diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java index 51e4709aa7c7..a7dfd35acf1b 100644 --- a/services/core/java/com/android/server/slice/SliceManagerService.java +++ b/services/core/java/com/android/server/slice/SliceManagerService.java @@ -149,11 +149,25 @@ public class SliceManagerService extends ISliceManager.Stub { /// ----- ISliceManager stuff ----- @Override + public Uri[] getPinnedSlices(String pkg) { + verifyCaller(pkg); + ArrayList<Uri> ret = new ArrayList<>(); + synchronized (mLock) { + for (PinnedSliceState state : mPinnedSlicesByUri.values()) { + if (Objects.equals(pkg, state.getPkg())) { + ret.add(state.getUri()); + } + } + } + return ret.toArray(new Uri[ret.size()]); + } + + @Override public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token) throws RemoteException { verifyCaller(pkg); enforceAccess(pkg, uri); uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier()); - getOrCreatePinnedSlice(uri).pin(pkg, specs, token); + getOrCreatePinnedSlice(uri, pkg).pin(pkg, specs, token); } @Override @@ -302,11 +316,11 @@ public class SliceManagerService extends ISliceManager.Stub { } } - private PinnedSliceState getOrCreatePinnedSlice(Uri uri) { + private PinnedSliceState getOrCreatePinnedSlice(Uri uri, String pkg) { synchronized (mLock) { PinnedSliceState manager = mPinnedSlicesByUri.get(uri); if (manager == null) { - manager = createPinnedSlice(uri); + manager = createPinnedSlice(uri, pkg); mPinnedSlicesByUri.put(uri, manager); } return manager; @@ -314,8 +328,8 @@ public class SliceManagerService extends ISliceManager.Stub { } @VisibleForTesting - protected PinnedSliceState createPinnedSlice(Uri uri) { - return new PinnedSliceState(this, uri); + protected PinnedSliceState createPinnedSlice(Uri uri, String pkg) { + return new PinnedSliceState(this, uri, pkg); } public Object getLock() { diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java index 64f77a2cc4ce..00e30507d232 100644 --- a/services/core/java/com/android/server/wm/AnimationAdapter.java +++ b/services/core/java/com/android/server/wm/AnimationAdapter.java @@ -17,13 +17,15 @@ package com.android.server.wm; import android.annotation.ColorInt; -import android.graphics.Point; +import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.animation.Animation; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; +import java.io.PrintWriter; + /** * Interface that describes an animation and bridges the animation start to the component * responsible for running the animation. @@ -83,4 +85,14 @@ interface AnimationAdapter { * @return the desired start time of the status bar transition, in uptime millis */ long getStatusBarTransitionsStartTime(); + + void dump(PrintWriter pw, String prefix); + + default void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + writeToProto(proto); + proto.end(token); + } + + void writeToProto(ProtoOutputStream proto); } diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index 40f772aaa529..1170148d6781 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -379,6 +379,8 @@ public class AppWindowContainerController if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken); wtoken.mAppStopped = false; + + mContainer.transferStartingWindowFromHiddenAboveTokenIfNeeded(); } // If we are preparing an app transition, then delay changing diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 267233750f55..fef615d651b1 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -187,6 +187,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree StartingSurface startingSurface; boolean startingDisplayed; boolean startingMoved; + // True if the hidden state of this token was forced to false due to a transferred starting // window. private boolean mHiddenSetFromTransferredStartingWindow; @@ -1091,7 +1092,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mService.registerAppFreezeListener(this); mService.mAppsFreezingScreen++; if (mService.mAppsFreezingScreen == 1) { - mService.startFreezingDisplayLocked(false, 0, 0, getDisplayContent()); + mService.startFreezingDisplayLocked(0, 0, getDisplayContent()); mService.mH.removeMessages(H.APP_FREEZE_TIMEOUT); mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000); } @@ -1136,6 +1137,25 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree stopFreezingScreen(true, true); } + /** + * Tries to transfer the starting window from a token that's above ourselves in the task but + * not visible anymore. This is a common scenario apps use: Trampoline activity T start main + * activity M in the same task. Now, when reopening the task, T starts on top of M but then + * immediately finishes after, so we have to transfer T to M. + */ + void transferStartingWindowFromHiddenAboveTokenIfNeeded() { + final Task task = getTask(); + for (int i = task.mChildren.size() - 1; i >= 0; i--) { + final AppWindowToken fromToken = task.mChildren.get(i); + if (fromToken == this) { + return; + } + if (fromToken.hiddenRequested && transferStartingWindow(fromToken.token)) { + return; + } + } + } + boolean transferStartingWindow(IBinder transferFrom) { final AppWindowToken fromToken = getDisplayContent().getAppWindowToken(transferFrom); if (fromToken == null) { diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java index f19cd0ff96f7..1977e126a8a0 100644 --- a/services/core/java/com/android/server/wm/BlackFrame.java +++ b/services/core/java/com/android/server/wm/BlackFrame.java @@ -41,7 +41,7 @@ public class BlackFrame { final int layer; final SurfaceControl surface; - BlackSurface(int layer, + BlackSurface(SurfaceControl.Transaction transaction, int layer, int l, int t, int r, int b, DisplayContent dc) throws OutOfResourcesException { left = l; top = t; @@ -56,24 +56,24 @@ public class BlackFrame { .setParent(null) // TODO: Work-around for b/69259549 .build(); - surface.setAlpha(1); - surface.setLayer(layer); - surface.show(); + transaction.setAlpha(surface, 1); + transaction.setLayer(surface, layer); + transaction.show(surface); if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM, " BLACK " + surface + ": CREATE layer=" + layer); } - void setAlpha(float alpha) { - surface.setAlpha(alpha); + void setAlpha(SurfaceControl.Transaction t, float alpha) { + t.setAlpha(surface, alpha); } - void setMatrix(Matrix matrix) { + void setMatrix(SurfaceControl.Transaction t, Matrix matrix) { mTmpMatrix.setTranslate(left, top); mTmpMatrix.postConcat(matrix); mTmpMatrix.getValues(mTmpFloats); - surface.setPosition(mTmpFloats[Matrix.MTRANS_X], + t.setPosition(surface, mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]); - surface.setMatrix( + t.setMatrix(surface, mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y], mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]); if (false) { @@ -87,8 +87,8 @@ public class BlackFrame { } } - void clearMatrix() { - surface.setMatrix(1, 0, 0, 1); + void clearMatrix(SurfaceControl.Transaction t) { + t.setMatrix(surface, 1, 0, 0, 1); } } @@ -113,7 +113,8 @@ public class BlackFrame { } } - public BlackFrame(Rect outer, Rect inner, int layer, DisplayContent dc, + public BlackFrame(SurfaceControl.Transaction t, + Rect outer, Rect inner, int layer, DisplayContent dc, boolean forceDefaultOrientation) throws OutOfResourcesException { boolean success = false; @@ -125,19 +126,19 @@ public class BlackFrame { mInnerRect = new Rect(inner); try { if (outer.top < inner.top) { - mBlackSurfaces[0] = new BlackSurface(layer, + mBlackSurfaces[0] = new BlackSurface(t, layer, outer.left, outer.top, inner.right, inner.top, dc); } if (outer.left < inner.left) { - mBlackSurfaces[1] = new BlackSurface(layer, + mBlackSurfaces[1] = new BlackSurface(t, layer, outer.left, inner.top, inner.left, outer.bottom, dc); } if (outer.bottom > inner.bottom) { - mBlackSurfaces[2] = new BlackSurface(layer, + mBlackSurfaces[2] = new BlackSurface(t, layer, inner.left, inner.bottom, outer.right, outer.bottom, dc); } if (outer.right > inner.right) { - mBlackSurfaces[3] = new BlackSurface(layer, + mBlackSurfaces[3] = new BlackSurface(t, layer, inner.right, outer.top, outer.right, inner.bottom, dc); } success = true; @@ -161,36 +162,36 @@ public class BlackFrame { } } - public void hide() { + public void hide(SurfaceControl.Transaction t) { if (mBlackSurfaces != null) { for (int i=0; i<mBlackSurfaces.length; i++) { if (mBlackSurfaces[i] != null) { - mBlackSurfaces[i].surface.hide(); + t.hide(mBlackSurfaces[i].surface); } } } } - public void setAlpha(float alpha) { + public void setAlpha(SurfaceControl.Transaction t, float alpha) { for (int i=0; i<mBlackSurfaces.length; i++) { if (mBlackSurfaces[i] != null) { - mBlackSurfaces[i].setAlpha(alpha); + mBlackSurfaces[i].setAlpha(t, alpha); } } } - public void setMatrix(Matrix matrix) { + public void setMatrix(SurfaceControl.Transaction t, Matrix matrix) { for (int i=0; i<mBlackSurfaces.length; i++) { if (mBlackSurfaces[i] != null) { - mBlackSurfaces[i].setMatrix(matrix); + mBlackSurfaces[i].setMatrix(t, matrix); } } } - public void clearMatrix() { + public void clearMatrix(SurfaceControl.Transaction t) { for (int i=0; i<mBlackSurfaces.length; i++) { if (mBlackSurfaces[i] != null) { - mBlackSurfaces[i].clearMatrix(); + mBlackSurfaces[i].clearMatrix(t); } } } diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index a180a3acfbed..5c62987ec521 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -16,11 +16,19 @@ package com.android.server.wm; -import android.view.SurfaceControl; +import static com.android.server.wm.proto.AlphaAnimationSpecProto.DURATION; +import static com.android.server.wm.proto.AlphaAnimationSpecProto.FROM; +import static com.android.server.wm.proto.AlphaAnimationSpecProto.TO; +import static com.android.server.wm.proto.AnimationSpecProto.ALPHA; + import android.graphics.Rect; +import android.util.proto.ProtoOutputStream; +import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; +import java.io.PrintWriter; + /** * Utility class for use by a WindowContainer implementation to add "DimLayer" support, that is * black layers of varying opacity at various Z-levels which create the effect of a Dim. @@ -334,5 +342,21 @@ class Dimmer { + mFromAlpha; t.setAlpha(sc, alpha); } + + @Override + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("from="); pw.print(mFromAlpha); + pw.print(" to="); pw.print(mToAlpha); + pw.print(" duration="); pw.println(mDuration); + } + + @Override + public void writeToProtoInner(ProtoOutputStream proto) { + final long token = proto.start(ALPHA); + proto.write(FROM, mFromAlpha); + proto.write(TO, mToAlpha); + proto.write(DURATION, mDuration); + proto.end(token); + } } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 2dce9133d094..59babcfe0371 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -258,7 +258,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * Current rotation of the display. * Constants as per {@link android.view.Surface.Rotation}. * - * @see #updateRotationUnchecked(boolean) + * @see #updateRotationUnchecked() */ private int mRotation = 0; @@ -274,7 +274,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * Flag indicating that the application is receiving an orientation that has different metrics * than it expected. E.g. Portrait instead of Landscape. * - * @see #updateRotationUnchecked(boolean) + * @see #updateRotationUnchecked() */ private boolean mAltOrientation = false; @@ -926,7 +926,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * Returns true if the rotation has been changed. In this case YOU MUST CALL * {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN. */ - boolean updateRotationUnchecked(boolean inTransaction) { + boolean updateRotationUnchecked() { if (mService.mDeferredRotationPauseCount > 0) { // Rotation updates have been paused temporarily. Defer the update until // updates have been resumed. @@ -1030,7 +1030,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mService.mPolicy.selectRotationAnimationLw(anim); if (!rotateSeamlessly) { - mService.startFreezingDisplayLocked(inTransaction, anim[0], anim[1], this); + mService.startFreezingDisplayLocked(anim[0], anim[1], this); // startFreezingDisplayLocked can reset the ScreenRotationAnimation. screenRotationAnimation = mService.mAnimator.getScreenRotationAnimationLocked( mDisplayId); @@ -1041,9 +1041,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // to their rotated state independently and without a freeze required. screenRotationAnimation = null; - // We have to reset this in case a window was removed before it - // finished seamless rotation. - mService.mSeamlessRotationCount = 0; + mService.startSeamlessRotation(); } // We need to update our screen size information to match the new rotation. If the rotation @@ -1053,40 +1051,27 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // #computeScreenConfiguration() later. updateDisplayAndOrientation(getConfiguration().uiMode); - if (!inTransaction) { - if (SHOW_TRANSACTIONS) { - Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked"); + // NOTE: We disable the rotation in the emulator because + // it doesn't support hardware OpenGL emulation yet. + if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null + && screenRotationAnimation.hasScreenshot()) { + if (screenRotationAnimation.setRotation(getPendingTransaction(), rotation, + MAX_ANIMATION_DURATION, mService.getTransitionAnimationScaleLocked(), + mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) { + mService.scheduleAnimationLocked(); } - mService.openSurfaceTransaction(); } - try { - // NOTE: We disable the rotation in the emulator because - // it doesn't support hardware OpenGL emulation yet. - if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null - && screenRotationAnimation.hasScreenshot()) { - if (screenRotationAnimation.setRotationInTransaction(rotation, - MAX_ANIMATION_DURATION, mService.getTransitionAnimationScaleLocked(), - mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) { - mService.scheduleAnimationLocked(); - } - } - if (rotateSeamlessly) { - forAllWindows(w -> { - w.mWinAnimator.seamlesslyRotateWindow(oldRotation, rotation); - }, true /* traverseTopToBottom */); - } - - mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager(); - } finally { - if (!inTransaction) { - mService.closeSurfaceTransaction("setRotationUnchecked"); - if (SHOW_LIGHT_TRANSACTIONS) { - Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked"); - } - } + if (rotateSeamlessly) { + forAllWindows(w -> { + w.mWinAnimator.seamlesslyRotateWindow(getPendingTransaction(), + oldRotation, rotation); + }, true /* traverseTopToBottom */); } + mService.mDisplayManagerInternal.performTraversal(getPendingTransaction()); + scheduleAnimation(); + forAllWindows(w -> { if (w.mHasSurface && !rotateSeamlessly) { if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w); @@ -2808,7 +2793,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) { if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout"); - if (mService.updateOrientationFromAppTokensLocked(true, mDisplayId)) { + if (mService.updateOrientationFromAppTokensLocked(mDisplayId)) { setLayoutNeeded(); mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mDisplayId).sendToTarget(); } diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java index 1b41cb84516d..3f1fde96d7b7 100644 --- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java @@ -16,12 +16,18 @@ package com.android.server.wm; +import static com.android.server.wm.proto.AnimationAdapterProto.LOCAL; +import static com.android.server.wm.proto.LocalAnimationAdapterProto.ANIMATION_SPEC; + import android.os.SystemClock; +import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; +import java.io.PrintWriter; + /** * Animation that can be executed without holding the window manager lock. See * {@link SurfaceAnimationRunner}. @@ -74,6 +80,18 @@ class LocalAnimationAdapter implements AnimationAdapter { return mSpec.calculateStatusBarTransitionStartTime(); } + @Override + public void dump(PrintWriter pw, String prefix) { + mSpec.dump(pw, prefix); + } + + @Override + public void writeToProto(ProtoOutputStream proto) { + final long token = proto.start(LOCAL); + mSpec.writeToProto(proto, ANIMATION_SPEC); + proto.end(token); + } + /** * Describes how to apply an animation. */ @@ -127,5 +145,15 @@ class LocalAnimationAdapter implements AnimationAdapter { default boolean canSkipFirstFrame() { return false; } + + void dump(PrintWriter pw, String prefix); + + default void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + writeToProtoInner(proto); + proto.end(token); + } + + void writeToProtoInner(ProtoOutputStream proto); } } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 39b886d336e7..0b0df6ff588d 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -23,6 +23,8 @@ import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.server.wm.proto.RemoteAnimationAdapterWrapperProto.TARGET; +import static com.android.server.wm.proto.AnimationAdapterProto.REMOTE; import android.app.ActivityManager.TaskSnapshot; import android.app.WindowConfiguration; @@ -33,18 +35,21 @@ import android.os.RemoteException; import android.os.SystemClock; import android.util.ArraySet; import android.util.Log; -import android.util.Slog; +import android.util.Slog;import android.util.proto.ProtoOutputStream; import android.util.SparseBooleanArray; +import android.util.proto.ProtoOutputStream; import android.view.IRecentsAnimationController; import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; -import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; + import com.google.android.collect.Sets; + +import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; + import java.io.PrintWriter; import java.util.ArrayList; - /** * Controls a single instance of the remote driven recents animation. In particular, this allows * the calling SystemUI to animate the visible task windows as a part of the transition. The remote @@ -136,6 +141,22 @@ public class RecentsAnimationController { } @Override + public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) + throws RemoteException { + long token = Binder.clearCallingIdentity(); + try { + synchronized (mService.getWindowManagerLock()) { + for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { + mPendingAnimations.get(i).mTask.setCanAffectSystemUiFlags(behindSystemBars); + } + mService.mWindowPlacerLocked.requestTraversal(); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override public void setInputConsumerEnabled(boolean enabled) { if (DEBUG) Log.d(TAG, "setInputConsumerEnabled(" + enabled + "): mCanceled=" + mCanceled); @@ -235,11 +256,16 @@ public class RecentsAnimationController { return; } try { - final RemoteAnimationTarget[] appAnimations = - new RemoteAnimationTarget[mPendingAnimations.size()]; + final ArrayList<RemoteAnimationTarget> appAnimations = new ArrayList<>(); for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { - appAnimations[i] = mPendingAnimations.get(i).createRemoteAnimationApp(); + final RemoteAnimationTarget target = + mPendingAnimations.get(i).createRemoteAnimationApp(); + if (target != null) { + appAnimations.add(target); + } } + final RemoteAnimationTarget[] appTargets = appAnimations.toArray( + new RemoteAnimationTarget[appAnimations.size()]); mPendingStart = false; final Rect minimizedHomeBounds = @@ -248,7 +274,7 @@ public class RecentsAnimationController { final Rect contentInsets = mHomeAppToken != null && mHomeAppToken.findMainWindow() != null ? mHomeAppToken.findMainWindow().mContentInsets : null; - mRunner.onAnimationStart_New(mController, appAnimations, contentInsets, + mRunner.onAnimationStart_New(mController, appTargets, contentInsets, minimizedHomeBounds); } catch (RemoteException e) { Slog.e(TAG, "Failed to start recents animation", e); @@ -279,6 +305,7 @@ public class RecentsAnimationController { + mPendingAnimations.size()); for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final TaskAnimationAdapter adapter = mPendingAnimations.get(i); + adapter.mTask.setCanAffectSystemUiFlags(true); adapter.mCapturedFinishCallback.onAnimationFinished(adapter); } mPendingAnimations.clear(); @@ -348,6 +375,7 @@ public class RecentsAnimationController { private SurfaceControl mCapturedLeash; private OnAnimationFinishedCallback mCapturedFinishCallback; private final boolean mIsRecentTaskInvisible; + private RemoteAnimationTarget mTarget; TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) { mTask = task; @@ -361,10 +389,14 @@ public class RecentsAnimationController { container.getRelativePosition(position); container.getBounds(bounds); final WindowState mainWindow = mTask.getTopVisibleAppMainWindow(); - return new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash, + if (mainWindow == null) { + return null; + } + mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash, !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect, mainWindow.mContentInsets, mTask.getPrefixOrderIndex(), position, bounds, mTask.getWindowConfiguration(), mIsRecentTaskInvisible); + return mTarget; } @Override @@ -403,6 +435,26 @@ public class RecentsAnimationController { public long getStatusBarTransitionsStartTime() { return SystemClock.uptimeMillis(); } + + @Override + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.println("task=" + mTask); + if (mTarget != null) { + pw.print(prefix); pw.println("Target:"); + mTarget.dump(pw, prefix + " "); + } else { + pw.print(prefix); pw.println("Target: null"); + } + } + + @Override + public void writeToProto(ProtoOutputStream proto) { + final long token = proto.start(REMOTE); + if (mTarget != null) { + mTarget.writeToProto(proto, TARGET); + } + proto.end(token); + } } public void dump(PrintWriter pw, String prefix) { diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 169d65e2bdbc..d645110b6fd5 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -16,8 +16,11 @@ package com.android.server.wm; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.server.wm.proto.AnimationAdapterProto.REMOTE; +import static com.android.server.wm.proto.RemoteAnimationAdapterWrapperProto.TARGET; import android.graphics.Point; import android.graphics.Rect; @@ -25,16 +28,18 @@ import android.os.Handler; import android.os.RemoteException; import android.os.SystemClock; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import android.view.IRemoteAnimationFinishedCallback; -import android.view.IRemoteAnimationFinishedCallback.Stub; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; +import com.android.internal.util.FastPrintWriter; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; -import java.lang.ref.WeakReference; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; /** @@ -104,6 +109,20 @@ class RemoteAnimationController { } }); sendRunningRemoteAnimation(true); + if (DEBUG_APP_TRANSITIONS) { + writeStartDebugStatement(); + } + } + + private void writeStartDebugStatement() { + Slog.i(TAG, "Starting remote animation"); + final StringWriter sw = new StringWriter(); + final FastPrintWriter pw = new FastPrintWriter(sw); + for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { + mPendingAnimations.get(i).dump(pw, ""); + } + pw.close(); + Slog.i(TAG, sw.toString()); } private RemoteAnimationTarget[] createAnimations() { @@ -133,6 +152,7 @@ class RemoteAnimationController { } } sendRunningRemoteAnimation(false); + if (DEBUG_APP_TRANSITIONS) Slog.i(TAG, "Finishing remote animation"); } private void invokeAnimationCancelled() { @@ -193,6 +213,7 @@ class RemoteAnimationController { private OnAnimationFinishedCallback mCapturedFinishCallback; private final Point mPosition = new Point(); private final Rect mStackBounds = new Rect(); + private RemoteAnimationTarget mTarget; RemoteAnimationAdapterWrapper(AppWindowToken appWindowToken, Point position, Rect stackBounds) { @@ -210,11 +231,12 @@ class RemoteAnimationController { if (mainWindow == null) { return null; } - return new RemoteAnimationTarget(task.mTaskId, getMode(), + mTarget = new RemoteAnimationTarget(task.mTaskId, getMode(), mCapturedLeash, !mAppWindowToken.fillsParent(), mainWindow.mWinAnimator.mLastClipRect, mainWindow.mContentInsets, mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds, task.getWindowConfiguration(), false /*isNotInRecents*/); + return mTarget; } private int getMode() { @@ -275,5 +297,25 @@ class RemoteAnimationController { return SystemClock.uptimeMillis() + mRemoteAnimationAdapter.getStatusBarTransitionDelay(); } + + @Override + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("token="); pw.println(mAppWindowToken); + if (mTarget != null) { + pw.print(prefix); pw.println("Target:"); + mTarget.dump(pw, prefix + " "); + } else { + pw.print(prefix); pw.println("Target: null"); + } + } + + @Override + public void writeToProto(ProtoOutputStream proto) { + final long token = proto.start(REMOTE); + if (mTarget != null) { + mTarget.writeToProto(proto, TARGET); + } + proto.end(token); + } } } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index f32c275b61f1..32ae52375fd5 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -37,6 +37,7 @@ import android.util.SparseIntArray; import android.util.proto.ProtoOutputStream; import android.view.Display; import android.view.DisplayInfo; +import android.view.SurfaceControl; import android.view.WindowManager; import com.android.internal.util.ArrayUtils; @@ -128,6 +129,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { private final Handler mHandler; private String mCloseSystemDialogsReason; + + // Only a seperate transaction until we seperate the apply surface changes + // transaction from the global transaction. + private final SurfaceControl.Transaction mDisplayTransaction = new SurfaceControl.Transaction(); + private final Consumer<WindowState> mCloseSystemDialogsConsumer = w -> { if (w.mHasSurface) { try { @@ -725,7 +731,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); // TODO(multi-display): Update rotation for different displays separately. final int displayId = defaultDisplay.getDisplayId(); - if (defaultDisplay.updateRotationUnchecked(false /* inTransaction */)) { + if (defaultDisplay.updateRotationUnchecked()) { mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } else { mUpdateRotation = false; @@ -735,7 +741,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { // PhoneWindowManager. final DisplayContent vrDisplay = mService.mVr2dDisplayId != INVALID_DISPLAY ? getDisplayContent(mService.mVr2dDisplayId) : null; - if (vrDisplay != null && vrDisplay.updateRotationUnchecked(false /* inTransaction */)) { + if (vrDisplay != null && vrDisplay.updateRotationUnchecked()) { mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mService.mVr2dDisplayId) .sendToTarget(); } @@ -835,7 +841,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { // Give the display manager a chance to adjust properties like display rotation if it needs // to. - mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager(); + mService.mDisplayManagerInternal.performTraversal(mDisplayTransaction); + SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction); } /** diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index 5a39de5c3242..ad2fabb70299 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -224,8 +224,7 @@ class ScreenRotationAnimation { } public ScreenRotationAnimation(Context context, DisplayContent displayContent, - boolean inTransaction, boolean forceDefaultOrientation, - boolean isSecure, WindowManagerService service) { + boolean forceDefaultOrientation, boolean isSecure, WindowManagerService service) { mService = service; mContext = context; mDisplayContent = displayContent; @@ -260,52 +259,39 @@ class ScreenRotationAnimation { mOriginalWidth = originalWidth; mOriginalHeight = originalHeight; - if (!inTransaction) { - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, - ">>> OPEN TRANSACTION ScreenRotationAnimation"); - mService.openSurfaceTransaction(); - } - + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); try { - try { - mSurfaceControl = displayContent.makeOverlay() - .setName("ScreenshotSurface") - .setSize(mWidth, mHeight) - .setSecure(isSecure) - .build(); - - // capture a screenshot into the surface we just created - Surface sur = new Surface(); - sur.copyFrom(mSurfaceControl); - // TODO(multidisplay): we should use the proper display - SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay( - SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur); - mSurfaceControl.setLayer(SCREEN_FREEZE_LAYER_SCREENSHOT); - mSurfaceControl.setAlpha(0); - mSurfaceControl.show(); - sur.destroy(); - } catch (OutOfResourcesException e) { - Slog.w(TAG, "Unable to allocate freeze surface", e); - } - - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM, - " FREEZE " + mSurfaceControl + ": CREATE"); - - setRotationInTransaction(originalRotation); - } finally { - if (!inTransaction) { - mService.closeSurfaceTransaction("ScreenRotationAnimation"); - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, - "<<< CLOSE TRANSACTION ScreenRotationAnimation"); - } - } + mSurfaceControl = displayContent.makeOverlay() + .setName("ScreenshotSurface") + .setSize(mWidth, mHeight) + .setSecure(isSecure) + .build(); + + // capture a screenshot into the surface we just created + Surface sur = new Surface(); + sur.copyFrom(mSurfaceControl); + // TODO(multidisplay): we should use the proper display + SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay( + SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur); + t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT); + t.setAlpha(mSurfaceControl, 0); + t.show(mSurfaceControl); + sur.destroy(); + } catch (OutOfResourcesException e) { + Slog.w(TAG, "Unable to allocate freeze surface", e); + } + + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM, + " FREEZE " + mSurfaceControl + ": CREATE"); + setRotation(t, originalRotation); + t.apply(); } boolean hasScreenshot() { return mSurfaceControl != null; } - private void setSnapshotTransformInTransaction(Matrix matrix, float alpha) { + private void setSnapshotTransform(SurfaceControl.Transaction t, Matrix matrix, float alpha) { if (mSurfaceControl != null) { matrix.getValues(mTmpFloats); float x = mTmpFloats[Matrix.MTRANS_X]; @@ -315,11 +301,11 @@ class ScreenRotationAnimation { x -= mCurrentDisplayRect.left; y -= mCurrentDisplayRect.top; } - mSurfaceControl.setPosition(x, y); - mSurfaceControl.setMatrix( + t.setPosition(mSurfaceControl, x, y); + t.setMatrix(mSurfaceControl, mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y], mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]); - mSurfaceControl.setAlpha(alpha); + t.setAlpha(mSurfaceControl, alpha); if (DEBUG_TRANSFORMS) { float[] srcPnts = new float[] { 0, 0, mWidth, mHeight }; float[] dstPnts = new float[4]; @@ -353,8 +339,7 @@ class ScreenRotationAnimation { } } - // Must be called while in a transaction. - private void setRotationInTransaction(int rotation) { + private void setRotation(SurfaceControl.Transaction t, int rotation) { mCurRotation = rotation; // Compute the transformation matrix that must be applied @@ -364,15 +349,14 @@ class ScreenRotationAnimation { createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix); if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta); - setSnapshotTransformInTransaction(mSnapshotInitialMatrix, 1.0f); + setSnapshotTransform(t, mSnapshotInitialMatrix, 1.0f); } - // Must be called while in a transaction. - public boolean setRotationInTransaction(int rotation, + public boolean setRotation(SurfaceControl.Transaction t, int rotation, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) { - setRotationInTransaction(rotation); + setRotation(t, rotation); if (TWO_PHASE_ANIMATION) { - return startAnimation(maxAnimationDuration, animationScale, + return startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight, false, 0, 0); } @@ -383,7 +367,7 @@ class ScreenRotationAnimation { /** * Returns true if animating. */ - private boolean startAnimation(long maxAnimationDuration, + private boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight, boolean dismissing, int exitAnim, int enterAnim) { if (mSurfaceControl == null) { @@ -542,11 +526,6 @@ class ScreenRotationAnimation { final int layerStack = mDisplayContent.getDisplay().getLayerStack(); if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) { - if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( - TAG_WM, - ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation"); - mService.openSurfaceTransaction(); - // Compute the transformation matrix that must be applied // the the black frame to make it stay in the initial position // before the new screen rotation. This is different than the @@ -559,24 +538,15 @@ class ScreenRotationAnimation { Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1, mOriginalWidth*2, mOriginalHeight*2); Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight); - mCustomBlackFrame = new BlackFrame(outer, inner, + mCustomBlackFrame = new BlackFrame(t, outer, inner, SCREEN_FREEZE_LAYER_CUSTOM, mDisplayContent, false); - mCustomBlackFrame.setMatrix(mFrameInitialMatrix); + mCustomBlackFrame.setMatrix(t, mFrameInitialMatrix); } catch (OutOfResourcesException e) { Slog.w(TAG, "Unable to allocate black surface", e); - } finally { - mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation"); - if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( - TAG_WM, - "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation"); } } if (!customAnim && mExitingBlackFrame == null) { - if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( - TAG_WM, - ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation"); - mService.openSurfaceTransaction(); try { // Compute the transformation matrix that must be applied // the the black frame to make it stay in the initial position @@ -599,38 +569,23 @@ class ScreenRotationAnimation { mOriginalWidth*2, mOriginalHeight*2); inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight); } - mExitingBlackFrame = new BlackFrame(outer, inner, + mExitingBlackFrame = new BlackFrame(t, outer, inner, SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation); - mExitingBlackFrame.setMatrix(mFrameInitialMatrix); + mExitingBlackFrame.setMatrix(t, mFrameInitialMatrix); } catch (OutOfResourcesException e) { Slog.w(TAG, "Unable to allocate black surface", e); - } finally { - mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation"); - if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( - TAG_WM, - "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation"); } } if (customAnim && mEnteringBlackFrame == null) { - if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( - TAG_WM, - ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation"); - mService.openSurfaceTransaction(); - try { Rect outer = new Rect(-finalWidth*1, -finalHeight*1, finalWidth*2, finalHeight*2); Rect inner = new Rect(0, 0, finalWidth, finalHeight); - mEnteringBlackFrame = new BlackFrame(outer, inner, + mEnteringBlackFrame = new BlackFrame(t, outer, inner, SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false); } catch (OutOfResourcesException e) { Slog.w(TAG, "Unable to allocate black surface", e); - } finally { - mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation"); - if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( - TAG_WM, - "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation"); } } @@ -640,7 +595,7 @@ class ScreenRotationAnimation { /** * Returns true if animating. */ - public boolean dismiss(long maxAnimationDuration, + public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) { if (DEBUG_STATE) Slog.v(TAG, "Dismiss!"); if (mSurfaceControl == null) { @@ -648,7 +603,7 @@ class ScreenRotationAnimation { return false; } if (!mStarted) { - startAnimation(maxAnimationDuration, animationScale, finalWidth, finalHeight, + startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight, true, exitAnim, enterAnim); } if (!mStarted) { @@ -919,7 +874,7 @@ class ScreenRotationAnimation { return more; } - void updateSurfacesInTransaction() { + void updateSurfaces(SurfaceControl.Transaction t) { if (!mStarted) { return; } @@ -927,28 +882,28 @@ class ScreenRotationAnimation { if (mSurfaceControl != null) { if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface"); - mSurfaceControl.hide(); + t.hide(mSurfaceControl); } } if (mCustomBlackFrame != null) { if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) { if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding black frame"); - mCustomBlackFrame.hide(); + mCustomBlackFrame.hide(t); } else { - mCustomBlackFrame.setMatrix(mFrameTransformation.getMatrix()); + mCustomBlackFrame.setMatrix(t, mFrameTransformation.getMatrix()); } } if (mExitingBlackFrame != null) { if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding exiting frame"); - mExitingBlackFrame.hide(); + mExitingBlackFrame.hide(t); } else { mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(), mFrameInitialMatrix); - mExitingBlackFrame.setMatrix(mExitFrameFinalMatrix); + mExitingBlackFrame.setMatrix(t, mExitFrameFinalMatrix); if (mForceDefaultOrientation) { - mExitingBlackFrame.setAlpha(mExitTransformation.getAlpha()); + mExitingBlackFrame.setAlpha(t, mExitTransformation.getAlpha()); } } } @@ -956,13 +911,13 @@ class ScreenRotationAnimation { if (mEnteringBlackFrame != null) { if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) { if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding entering frame"); - mEnteringBlackFrame.hide(); + mEnteringBlackFrame.hide(t); } else { - mEnteringBlackFrame.setMatrix(mEnterTransformation.getMatrix()); + mEnteringBlackFrame.setMatrix(t, mEnterTransformation.getMatrix()); } } - setSnapshotTransformInTransaction(mSnapshotFinalMatrix, mExitTransformation.getAlpha()); + setSnapshotTransform(t, mSnapshotFinalMatrix, mExitTransformation.getAlpha()); } public boolean stepAnimationLocked(long now) { diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 76f5396bcb48..c06caaf9e900 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -313,7 +313,9 @@ class SurfaceAnimator { */ void writeToProto(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); - proto.write(ANIMATION_ADAPTER, mAnimation != null ? mAnimation.toString() : "null"); + if (mAnimation != null) { + mAnimation.writeToProto(proto, ANIMATION_ADAPTER); + } if (mLeash != null){ mLeash.writeToProto(proto, LEASH); } @@ -322,8 +324,18 @@ class SurfaceAnimator { } void dump(PrintWriter pw, String prefix) { - pw.print(prefix); pw.print("mAnimation="); pw.print(mAnimation); - pw.print(" mLeash="); pw.println(mLeash); + pw.print(prefix); pw.print("mLeash="); pw.print(mLeash); + if (mAnimationStartDelayed) { + pw.print(" mAnimationStartDelayed="); pw.println(mAnimationStartDelayed); + } else { + pw.println(); + } + pw.print(prefix); pw.println("Animation:"); + if (mAnimation != null) { + mAnimation.dump(pw, prefix + " "); + } else { + pw.print(prefix); pw.println("null"); + } } /** diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 2e86351ee4c2..a403e6f2a212 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -96,6 +96,9 @@ class Task extends WindowContainer<AppWindowToken> { private Dimmer mDimmer = new Dimmer(this); private final Rect mTmpDimBoundsRect = new Rect(); + /** @see #setCanAffectSystemUiFlags */ + private boolean mCanAffectSystemUiFlags = true; + Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode, boolean supportsPictureInPicture, TaskDescription taskDescription, TaskWindowContainerController controller) { @@ -627,6 +630,21 @@ class Task extends WindowContainer<AppWindowToken> { callback.accept(this); } + /** + * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI + * flags. See {@link WindowState#canAffectSystemUiFlags()}. + */ + void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) { + mCanAffectSystemUiFlags = canAffectSystemUiFlags; + } + + /** + * @see #setCanAffectSystemUiFlags + */ + boolean canAffectSystemUiFlags() { + return mCanAffectSystemUiFlags; + } + @Override public String toString() { return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}"; diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java index 43fa3d56914e..a41eba8205f7 100644 --- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java +++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java @@ -19,10 +19,13 @@ package com.android.server.wm; import static com.android.server.wm.AnimationAdapter.STATUS_BAR_TRANSITION_DURATION; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; +import static com.android.server.wm.proto.AnimationSpecProto.WINDOW; +import static com.android.server.wm.proto.WindowAnimationSpecProto.ANIMATION; import android.graphics.Point; import android.graphics.Rect; import android.os.SystemClock; +import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.animation.Animation; @@ -33,6 +36,8 @@ import android.view.animation.TranslateAnimation; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; +import java.io.PrintWriter; + /** * Animation spec for regular window animations. */ @@ -129,6 +134,18 @@ public class WindowAnimationSpec implements AnimationSpec { return mCanSkipFirstFrame; } + @Override + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.println(mAnimation); + } + + @Override + public void writeToProtoInner(ProtoOutputStream proto) { + final long token = proto.start(WINDOW); + proto.write(ANIMATION, mAnimation.toString()); + proto.end(token); + } + /** * Tries to find a {@link TranslateAnimation} inside the {@code animation}. * diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index ab1019779b0b..793ffce2466e 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -30,6 +30,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; import android.view.Choreographer; +import android.view.SurfaceControl; import com.android.server.AnimationThread; import com.android.server.policy.WindowManagerPolicy; @@ -94,6 +95,8 @@ public class WindowAnimator { private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>(); private boolean mInExecuteAfterPrepareSurfacesRunnables; + private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); + WindowAnimator(final WindowManagerService service) { mService = service; mContext = service.mContext; @@ -203,7 +206,7 @@ public class WindowAnimator { final ScreenRotationAnimation screenRotationAnimation = mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation; if (screenRotationAnimation != null) { - screenRotationAnimation.updateSurfacesInTransaction(); + screenRotationAnimation.updateSurfaces(mTransaction); } orAnimating(dc.getDockedDividerController().animate(mCurrentTime)); //TODO (multidisplay): Magnification is supported only for the default display. @@ -219,6 +222,8 @@ public class WindowAnimator { if (mService.mWatermark != null) { mService.mWatermark.drawIfNeeded(); } + + SurfaceControl.mergeToGlobalTransaction(mTransaction); } catch (RuntimeException e) { Slog.wtf(TAG, "Unhandled exception in Window Manager", e); } finally { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 563d7928bb8d..be009d2af8ff 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -667,11 +667,18 @@ public class WindowManagerService extends IWindowManager.Stub WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; SettingsObserver mSettingsObserver; - // A count of the windows which are 'seamlessly rotated', e.g. a surface - // at an old orientation is being transformed. We freeze orientation updates - // while any windows are seamlessly rotated, so we need to track when this - // hits zero so we can apply deferred orientation updates. - int mSeamlessRotationCount = 0; + /** + * A count of the windows which are 'seamlessly rotated', e.g. a surface + * at an old orientation is being transformed. We freeze orientation updates + * while any windows are seamlessly rotated, so we need to track when this + * hits zero so we can apply deferred orientation updates. + */ + private int mSeamlessRotationCount = 0; + /** + * True in the interval from starting seamless rotation until the last rotated + * window draws in the new orientation. + */ + private boolean mRotatingSeamlessly = false; private final class SettingsObserver extends ContentObserver { private final Uri mDisplayInversionEnabledUri = @@ -809,6 +816,8 @@ public class WindowManagerService extends IWindowManager.Stub SurfaceBuilderFactory mSurfaceBuilderFactory = SurfaceControl.Builder::new; TransactionFactory mTransactionFactory = SurfaceControl.Transaction::new; + private final SurfaceControl.Transaction mTransaction = mTransactionFactory.make(); + static void boostPriorityForLockedSection() { sThreadPriorityBooster.boost(); } @@ -1487,7 +1496,7 @@ public class WindowManagerService extends IWindowManager.Stub if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addWindow: New client " + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5)); - if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false, displayId)) { + if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(displayId)) { reportNewConfig = true; } } @@ -2049,7 +2058,7 @@ public class WindowManagerService extends IWindowManager.Stub Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: updateOrientationFromAppTokens"); - configChanged = updateOrientationFromAppTokensLocked(false, displayId); + configChanged = updateOrientationFromAppTokensLocked(displayId); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (toBeDisplayed && win.mIsWallpaper) { @@ -2340,7 +2349,7 @@ public class WindowManagerService extends IWindowManager.Stub } Configuration config = null; - if (updateOrientationFromAppTokensLocked(false, displayId)) { + if (updateOrientationFromAppTokensLocked(displayId)) { // If we changed the orientation but mOrientationChangeComplete is already true, // we used seamless rotation, and we don't need to freeze the screen. if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) { @@ -2367,7 +2376,7 @@ public class WindowManagerService extends IWindowManager.Stub int anim[] = new int[2]; mPolicy.selectRotationAnimationLw(anim); - startFreezingDisplayLocked(false, anim[0], anim[1], displayContent); + startFreezingDisplayLocked(anim[0], anim[1], displayContent); config = new Configuration(mTempConfiguration); } } @@ -2387,7 +2396,7 @@ public class WindowManagerService extends IWindowManager.Stub * tokens. * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int) */ - boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) { + boolean updateOrientationFromAppTokensLocked(int displayId) { long ident = Binder.clearCallingIdentity(); try { final DisplayContent dc = mRoot.getDisplayContent(displayId); @@ -2400,7 +2409,7 @@ public class WindowManagerService extends IWindowManager.Stub if (dc.isDefaultDisplay) { mPolicy.setCurrentOrientationLw(req); } - if (dc.updateRotationUnchecked(inTransaction)) { + if (dc.updateRotationUnchecked()) { // changed return true; } @@ -2873,7 +2882,7 @@ public class WindowManagerService extends IWindowManager.Stub mClientFreezingScreen = true; final long origId = Binder.clearCallingIdentity(); try { - startFreezingDisplayLocked(false, exitAnim, enterAnim); + startFreezingDisplayLocked(exitAnim, enterAnim); mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT); mH.sendEmptyMessageDelayed(H.CLIENT_FREEZE_TIMEOUT, 5000); } finally { @@ -3774,8 +3783,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mDeferredRotationPauseCount == 0) { // TODO(multi-display): Update rotation for different displays separately. final DisplayContent displayContent = getDefaultDisplayContentLocked(); - final boolean changed = displayContent.updateRotationUnchecked( - false /* inTransaction */); + final boolean changed = displayContent.updateRotationUnchecked(); if (changed) { mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId()) .sendToTarget(); @@ -3800,8 +3808,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mWindowMap) { final DisplayContent displayContent = getDefaultDisplayContentLocked(); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: display"); - rotationChanged = displayContent.updateRotationUnchecked( - false /* inTransaction */); + rotationChanged = displayContent.updateRotationUnchecked(); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (!rotationChanged || forceRelayout) { displayContent.setLayoutNeeded(); @@ -5326,8 +5333,7 @@ public class WindowManagerService extends IWindowManager.Stub displayContent.setLayoutNeeded(); final int displayId = displayContent.getDisplayId(); - boolean configChanged = updateOrientationFromAppTokensLocked(false /* inTransaction */, - displayId); + boolean configChanged = updateOrientationFromAppTokensLocked(displayId); final Configuration currentDisplayConfig = displayContent.getConfiguration(); mTempConfiguration.setTo(currentDisplayConfig); displayContent.computeScreenConfiguration(mTempConfiguration); @@ -5335,7 +5341,7 @@ public class WindowManagerService extends IWindowManager.Stub if (configChanged) { mWaitingForConfig = true; - startFreezingDisplayLocked(false /* inTransaction */, 0 /* exitAnim */, + startFreezingDisplayLocked(0 /* exitAnim */, 0 /* enterAnim */, displayContent); mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } @@ -5651,14 +5657,14 @@ public class WindowManagerService extends IWindowManager.Stub return false; } - void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) { - startFreezingDisplayLocked(inTransaction, exitAnim, enterAnim, + void startFreezingDisplayLocked(int exitAnim, int enterAnim) { + startFreezingDisplayLocked(exitAnim, enterAnim, getDefaultDisplayContentLocked()); } - void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim, + void startFreezingDisplayLocked(int exitAnim, int enterAnim, DisplayContent displayContent) { - if (mDisplayFrozen) { + if (mDisplayFrozen || mRotatingSeamlessly) { return; } @@ -5669,8 +5675,8 @@ public class WindowManagerService extends IWindowManager.Stub } if (DEBUG_ORIENTATION) Slog.d(TAG_WM, - "startFreezingDisplayLocked: inTransaction=" + inTransaction - + " exitAnim=" + exitAnim + " enterAnim=" + enterAnim + "startFreezingDisplayLocked: exitAnim=" + + exitAnim + " enterAnim=" + enterAnim + " called by " + Debug.getCallers(8)); mScreenFrozenLock.acquire(); @@ -5714,7 +5720,7 @@ public class WindowManagerService extends IWindowManager.Stub displayContent.updateDisplayInfo(); screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent, - inTransaction, mPolicy.isDefaultOrientationForced(), isSecure, + mPolicy.isDefaultOrientationForced(), isSecure, this); mAnimator.setScreenRotationAnimationLocked(mFrozenDisplayId, screenRotationAnimation); @@ -5777,9 +5783,10 @@ public class WindowManagerService extends IWindowManager.Stub if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, false)) { mExitAnimId = mEnterAnimId = 0; } - if (screenRotationAnimation.dismiss(MAX_ANIMATION_DURATION, + if (screenRotationAnimation.dismiss(mTransaction, MAX_ANIMATION_DURATION, getTransitionAnimationScaleLocked(), displayInfo.logicalWidth, displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) { + mTransaction.apply(); scheduleAnimationLocked(); } else { screenRotationAnimation.kill(); @@ -5802,7 +5809,7 @@ public class WindowManagerService extends IWindowManager.Stub // to avoid inconsistent states. However, something interesting // could have actually changed during that time so re-evaluate it // now to catch that. - configChanged = updateOrientationFromAppTokensLocked(false, displayId); + configChanged = updateOrientationFromAppTokensLocked(displayId); // A little kludge: a lot could have happened while the // display was frozen, so now that we are coming back we @@ -5816,8 +5823,7 @@ public class WindowManagerService extends IWindowManager.Stub if (updateRotation) { if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation"); - configChanged |= displayContent.updateRotationUnchecked( - false /* inTransaction */); + configChanged |= displayContent.updateRotationUnchecked(); } if (configChanged) { @@ -7027,8 +7033,10 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) { Slog.i(TAG, "Performing post-rotate rotation after seamless rotation"); } + finishSeamlessRotation(); + final DisplayContent displayContent = w.getDisplayContent(); - if (displayContent.updateRotationUnchecked(false /* inTransaction */)) { + if (displayContent.updateRotationUnchecked()) { mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId()) .sendToTarget(); } @@ -7438,5 +7446,31 @@ public class WindowManagerService extends IWindowManager.Stub mH.obtainMessage(H.SET_RUNNING_REMOTE_ANIMATION, pid, runningRemoteAnimation ? 1 : 0) .sendToTarget(); } -} + void startSeamlessRotation() { + // We are careful to reset this in case a window was removed before it finished + // seamless rotation. + mSeamlessRotationCount = 0; + + mRotatingSeamlessly = true; + } + + void finishSeamlessRotation() { + mRotatingSeamlessly = false; + } + + /** + * Called when the state of lock task mode changes. This should be used to disable immersive + * mode confirmation. + * + * @param lockTaskState the new lock task mode state. One of + * {@link ActivityManager#LOCK_TASK_MODE_NONE}, + * {@link ActivityManager#LOCK_TASK_MODE_LOCKED}, + * {@link ActivityManager#LOCK_TASK_MODE_PINNED}. + */ + public void onLockTaskStateChanged(int lockTaskState) { + synchronized (mWindowMap) { + mPolicy.onLockTaskStateChangedLw(lockTaskState); + } + } +} diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index f01dc205ff1c..8866fe59b9f8 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -113,6 +113,10 @@ import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW; import static com.android.server.wm.proto.IdentifierProto.HASH_CODE; import static com.android.server.wm.proto.IdentifierProto.TITLE; import static com.android.server.wm.proto.IdentifierProto.USER_ID; +import static com.android.server.wm.proto.AnimationSpecProto.MOVE; +import static com.android.server.wm.proto.MoveAnimationSpecProto.DURATION; +import static com.android.server.wm.proto.MoveAnimationSpecProto.FROM; +import static com.android.server.wm.proto.MoveAnimationSpecProto.TO; import static com.android.server.wm.proto.WindowStateProto.ANIMATING_EXIT; import static com.android.server.wm.proto.WindowStateProto.ANIMATOR; import static com.android.server.wm.proto.WindowStateProto.ATTRIBUTES; @@ -1569,7 +1573,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final boolean exiting = mAnimatingExit || mDestroying; return shown && !exiting; } else { - return !mAppToken.isHidden(); + final Task task = getTask(); + final boolean canFromTask = task != null && task.canAffectSystemUiFlags(); + return canFromTask && !mAppToken.isHidden(); } } @@ -2009,7 +2015,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP removeImmediately(); // Removing a visible window will effect the computed orientation // So just update orientation if needed. - if (wasVisible && mService.updateOrientationFromAppTokensLocked(false, displayId)) { + if (wasVisible && mService.updateOrientationFromAppTokensLocked(displayId)) { mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); @@ -4724,5 +4730,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP t.setPosition(leash, mFrom.x + (mTo.x - mFrom.x) * v, mFrom.y + (mTo.y - mFrom.y) * v); } + + @Override + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("from="); pw.print(mFrom); + pw.print(" to="); pw.print(mTo); + pw.print(" duration="); pw.println(mDuration); + } + + @Override + public void writeToProtoInner(ProtoOutputStream proto) { + final long token = proto.start(MOVE); + mFrom.writeToProto(proto, FROM); + mTo.writeToProto(proto, TO); + proto.write(DURATION, mDuration); + proto.end(token); + } } } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 13f05e088cb1..46a9961e1bc1 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1415,7 +1415,8 @@ class WindowStateAnimator { } } - void seamlesslyRotateWindow(int oldRotation, int newRotation) { + void seamlesslyRotateWindow(SurfaceControl.Transaction t, + int oldRotation, int newRotation) { final WindowState w = mWin; if (!w.isVisibleNow() || w.mIsWallpaper) { return; @@ -1456,11 +1457,9 @@ class WindowStateAnimator { float DsDy = mService.mTmpFloats[Matrix.MSCALE_Y]; float nx = mService.mTmpFloats[Matrix.MTRANS_X]; float ny = mService.mTmpFloats[Matrix.MTRANS_Y]; - mSurfaceController.setPositionInTransaction(nx, ny, false); - mSurfaceController.setMatrixInTransaction(DsDx * w.mHScale, - DtDx * w.mVScale, - DtDy * w.mHScale, - DsDy * w.mVScale, false); + mSurfaceController.setPosition(t, nx, ny, false); + mSurfaceController.setMatrix(t, DsDx * w.mHScale, DtDx * w.mVScale, DtDy + * w.mHScale, DsDy * w.mVScale, false); } /** The force-scaled state for a given window can persist past diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index 9d6f8f78c272..f6c0a54c74ca 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -242,6 +242,11 @@ class WindowSurfaceController { } void setPositionInTransaction(float left, float top, boolean recoveringMemory) { + setPosition(null, left, top, recoveringMemory); + } + + void setPosition(SurfaceControl.Transaction t, float left, float top, + boolean recoveringMemory) { final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top; if (surfaceMoved) { mSurfaceX = left; @@ -251,7 +256,11 @@ class WindowSurfaceController { if (SHOW_TRANSACTIONS) logSurface( "POS (setPositionInTransaction) @ (" + left + "," + top + ")", null); - mSurfaceControl.setPosition(left, top); + if (t == null) { + mSurfaceControl.setPosition(left, top); + } else { + t.setPosition(mSurfaceControl, left, top); + } } catch (RuntimeException e) { Slog.w(TAG, "Error positioning surface of " + this + " pos=(" + left + "," + top + ")", e); @@ -268,6 +277,11 @@ class WindowSurfaceController { void setMatrixInTransaction(float dsdx, float dtdx, float dtdy, float dsdy, boolean recoveringMemory) { + setMatrix(null, dsdx, dtdx, dtdy, dsdy, false); + } + + void setMatrix(SurfaceControl.Transaction t, float dsdx, float dtdx, + float dtdy, float dsdy, boolean recoveringMemory) { final boolean matrixChanged = mLastDsdx != dsdx || mLastDtdx != dtdx || mLastDtdy != dtdy || mLastDsdy != dsdy; if (!matrixChanged) { @@ -282,8 +296,11 @@ class WindowSurfaceController { try { if (SHOW_TRANSACTIONS) logSurface( "MATRIX [" + dsdx + "," + dtdx + "," + dtdy + "," + dsdy + "]", null); - mSurfaceControl.setMatrix( - dsdx, dtdx, dtdy, dsdy); + if (t == null) { + mSurfaceControl.setMatrix(dsdx, dtdx, dtdy, dsdy); + } else { + t.setMatrix(mSurfaceControl, dsdx, dtdx, dtdy, dsdy); + } } catch (RuntimeException e) { // If something goes wrong with the surface (such // as running out of memory), don't take down the diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 417959087de2..fc5e33a7bc5a 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -52,6 +52,7 @@ import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES; +import android.app.WindowConfiguration; import android.os.Debug; import android.os.Trace; import android.util.ArraySet; @@ -294,12 +295,14 @@ class WindowSurfacePlacer { // what will control the animation theme. If all closing windows are obscured, then there is // no need to do an animation. This is the case, for example, when this transition is being // done behind a dream window. + final ArraySet<Integer> activityTypes = collectActivityTypes(mService.mOpeningApps, + mService.mClosingApps); final AppWindowToken animLpToken = mService.mPolicy.allowAppAnimationsLw() - ? findAnimLayoutParamsToken(transit) + ? findAnimLayoutParamsToken(transit, activityTypes) : null; final LayoutParams animLp = getAnimLp(animLpToken); - overrideWithRemoteAnimationIfSet(animLpToken, transit); + overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes); final boolean voiceInteraction = containsVoiceInteraction(mService.mOpeningApps) || containsVoiceInteraction(mService.mOpeningApps); @@ -361,13 +364,14 @@ class WindowSurfacePlacer { * Overrides the pending transition with the remote animation defined for the transition in the * set of defined remote animations in the app window token. */ - private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit) { + private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit, + ArraySet<Integer> activityTypes) { if (animLpToken == null) { return; } final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition(); if (definition != null) { - final RemoteAnimationAdapter adapter = definition.getAdapter(transit); + final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes); if (adapter != null) { mService.mAppTransition.overridePendingAppTransitionRemote(adapter); } @@ -377,13 +381,14 @@ class WindowSurfacePlacer { /** * @return The window token that determines the animation theme. */ - private AppWindowToken findAnimLayoutParamsToken(@TransitionType int transit) { + private AppWindowToken findAnimLayoutParamsToken(@TransitionType int transit, + ArraySet<Integer> activityTypes) { AppWindowToken result; // Remote animations always win, but fullscreen tokens override non-fullscreen tokens. result = lookForHighestTokenWithFilter(mService.mClosingApps, mService.mOpeningApps, w -> w.getRemoteAnimationDefinition() != null - && w.getRemoteAnimationDefinition().hasTransition(transit)); + && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes)); if (result != null) { return result; } @@ -396,6 +401,22 @@ class WindowSurfacePlacer { w -> w.findMainWindow() != null); } + /** + * @return The set of {@link WindowConfiguration.ActivityType}s contained in the set of apps in + * {@code array1} and {@code array2}. + */ + private ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1, + ArraySet<AppWindowToken> array2) { + final ArraySet<Integer> result = new ArraySet<>(); + for (int i = array1.size() - 1; i >= 0; i--) { + result.add(array1.valueAt(i).getActivityType()); + } + for (int i = array2.size() - 1; i >= 0; i--) { + result.add(array2.valueAt(i).getActivityType()); + } + return result; + } + private AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1, ArraySet<AppWindowToken> array2, Predicate<AppWindowToken> filter) { final int array1count = array1.size(); @@ -403,12 +424,9 @@ class WindowSurfacePlacer { int bestPrefixOrderIndex = Integer.MIN_VALUE; AppWindowToken bestToken = null; for (int i = 0; i < count; i++) { - final AppWindowToken wtoken; - if (i < array1count) { - wtoken = array1.valueAt(i); - } else { - wtoken = array2.valueAt(i - array1count); - } + final AppWindowToken wtoken = i < array1count + ? array1.valueAt(i) + : array2.valueAt(i - array1count); final int prefixOrderIndex = wtoken.getPrefixOrderIndex(); if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) { bestPrefixOrderIndex = prefixOrderIndex; @@ -559,7 +577,8 @@ class WindowSurfacePlacer { + wtoken.allDrawn + " startingDisplayed=" + wtoken.startingDisplayed + " startingMoved=" + wtoken.startingMoved + " isRelaunching()=" - + wtoken.isRelaunching()); + + wtoken.isRelaunching() + " startingWindow=" + + wtoken.startingWindow); final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching(); diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk index aed57e3b6dcc..3d7fdbdd7436 100644 --- a/services/robotests/Android.mk +++ b/services/robotests/Android.mk @@ -62,7 +62,8 @@ LOCAL_SRC_FILES := \ $(call all-java-files-under, ../../core/java/android/app/backup) \ $(call all-Iaidl-files-under, ../../core/java/android/app/backup) \ ../../core/java/android/content/pm/PackageInfo.java \ - ../../core/java/android/app/IBackupAgent.aidl + ../../core/java/android/app/IBackupAgent.aidl \ + ../../core/java/android/util/KeyValueSettingObserver.java LOCAL_AIDL_INCLUDES := \ $(call all-Iaidl-files-under, $(INTERNAL_BACKUP)) \ diff --git a/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java b/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java index 0752537abfcc..2a32c2eef6ca 100644 --- a/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java +++ b/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java @@ -18,79 +18,218 @@ package com.android.server.backup; import static com.google.common.truth.Truth.assertThat; -import android.app.AlarmManager; +import android.content.ContentResolver; import android.content.Context; import android.os.Handler; import android.platform.test.annotations.Presubmit; import android.provider.Settings; - +import android.util.KeyValueSettingObserver; import com.android.server.testing.FrameworkRobolectricTestRunner; import com.android.server.testing.SystemLoaderClasses; import com.android.server.testing.SystemLoaderPackages; - +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(FrameworkRobolectricTestRunner.class) @Config(manifest = Config.NONE, sdk = 26) @SystemLoaderPackages({"com.android.server.backup"}) +@SystemLoaderClasses({KeyValueSettingObserver.class}) @Presubmit public class BackupManagerConstantsTest { private static final String PACKAGE_NAME = "some.package.name"; private static final String ANOTHER_PACKAGE_NAME = "another.package.name"; + private ContentResolver mContentResolver; + private BackupManagerConstants mConstants; + @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); + public void setUp() { + final Context context = RuntimeEnvironment.application.getApplicationContext(); + + mContentResolver = context.getContentResolver(); + mConstants = new BackupManagerConstants(new Handler(), mContentResolver); + mConstants.start(); + } + + @After + public void tearDown() { + mConstants.stop(); } @Test - public void testDefaultValues() throws Exception { - final Context context = RuntimeEnvironment.application.getApplicationContext(); - final Handler handler = new Handler(); + public void testGetConstants_afterConstructorWithStart_returnsDefaultValues() { + long keyValueBackupIntervalMilliseconds = + mConstants.getKeyValueBackupIntervalMilliseconds(); + long keyValueBackupFuzzMilliseconds = mConstants.getKeyValueBackupFuzzMilliseconds(); + boolean keyValueBackupRequireCharging = mConstants.getKeyValueBackupRequireCharging(); + int keyValueBackupRequiredNetworkType = mConstants.getKeyValueBackupRequiredNetworkType(); + long fullBackupIntervalMilliseconds = mConstants.getFullBackupIntervalMilliseconds(); + boolean fullBackupRequireCharging = mConstants.getFullBackupRequireCharging(); + int fullBackupRequiredNetworkType = mConstants.getFullBackupRequiredNetworkType(); + String[] backupFinishedNotificationReceivers = + mConstants.getBackupFinishedNotificationReceivers(); + + assertThat(keyValueBackupIntervalMilliseconds) + .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS); + assertThat(keyValueBackupFuzzMilliseconds) + .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS); + assertThat(keyValueBackupRequireCharging) + .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING); + assertThat(keyValueBackupRequiredNetworkType) + .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE); + assertThat(fullBackupIntervalMilliseconds) + .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS); + assertThat(fullBackupRequireCharging) + .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRE_CHARGING); + assertThat(fullBackupRequiredNetworkType) + .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE); + assertThat(backupFinishedNotificationReceivers).isEqualTo(new String[0]); + } - Settings.Secure.putString( - context.getContentResolver(), Settings.Secure.BACKUP_MANAGER_CONSTANTS, null); - - final BackupManagerConstants constants = - new BackupManagerConstants(handler, context.getContentResolver()); - - assertThat(constants.getKeyValueBackupIntervalMilliseconds()) - .isEqualTo(4 * AlarmManager.INTERVAL_HOUR); - assertThat(constants.getKeyValueBackupFuzzMilliseconds()).isEqualTo(10 * 60 * 1000); - assertThat(constants.getKeyValueBackupRequireCharging()).isEqualTo(true); - assertThat(constants.getKeyValueBackupRequiredNetworkType()).isEqualTo(1); - - assertThat(constants.getFullBackupIntervalMilliseconds()) - .isEqualTo(24 * AlarmManager.INTERVAL_HOUR); - assertThat(constants.getFullBackupRequireCharging()).isEqualTo(true); - assertThat(constants.getFullBackupRequiredNetworkType()).isEqualTo(2); - assertThat(constants.getBackupFinishedNotificationReceivers()).isEqualTo(new String[0]); + /** + * Tests that if there is a setting change when we are not currently observing the setting, that + * once we start observing again, we receive the most up-to-date value. + */ + @Test + public void testGetConstant_withSettingChangeBeforeStart_updatesValues() { + mConstants.stop(); + long testInterval = + BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS * 2; + final String setting = + BackupManagerConstants.KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS + "=" + testInterval; + putStringAndNotify(setting); + + mConstants.start(); + + long keyValueBackupIntervalMilliseconds = + mConstants.getKeyValueBackupIntervalMilliseconds(); + assertThat(keyValueBackupIntervalMilliseconds).isEqualTo(testInterval); } @Test - public void testParseNotificationReceivers() throws Exception { - final Context context = RuntimeEnvironment.application.getApplicationContext(); - final Handler handler = new Handler(); + public void testGetConstants_whenSettingIsNull_returnsDefaultValues() { + putStringAndNotify(null); + + long keyValueBackupIntervalMilliseconds = + mConstants.getKeyValueBackupIntervalMilliseconds(); + long keyValueBackupFuzzMilliseconds = mConstants.getKeyValueBackupFuzzMilliseconds(); + boolean keyValueBackupRequireCharging = mConstants.getKeyValueBackupRequireCharging(); + int keyValueBackupRequiredNetworkType = mConstants.getKeyValueBackupRequiredNetworkType(); + long fullBackupIntervalMilliseconds = mConstants.getFullBackupIntervalMilliseconds(); + boolean fullBackupRequireCharging = mConstants.getFullBackupRequireCharging(); + int fullBackupRequiredNetworkType = mConstants.getFullBackupRequiredNetworkType(); + String[] backupFinishedNotificationReceivers = + mConstants.getBackupFinishedNotificationReceivers(); + + assertThat(keyValueBackupIntervalMilliseconds) + .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS); + assertThat(keyValueBackupFuzzMilliseconds) + .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS); + assertThat(keyValueBackupRequireCharging) + .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING); + assertThat(keyValueBackupRequiredNetworkType) + .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE); + assertThat(fullBackupIntervalMilliseconds) + .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS); + assertThat(fullBackupRequireCharging) + .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRE_CHARGING); + assertThat(fullBackupRequiredNetworkType) + .isEqualTo(BackupManagerConstants.DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE); + assertThat(backupFinishedNotificationReceivers).isEqualTo(new String[0]); + } - final String recieversSetting = - "backup_finished_notification_receivers=" + /** + * Test passing in a malformed setting string. The setting expects + * "key1=value,key2=value,key3=value..." but we pass in "key1=,value" + */ + @Test + public void testGetConstant_whenSettingIsMalformed_doesNotUpdateParamsOrThrow() { + long testFuzz = BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS * 2; + final String invalidSettingFormat = + BackupManagerConstants.KEY_VALUE_BACKUP_FUZZ_MILLISECONDS + "=," + testFuzz; + putStringAndNotify(invalidSettingFormat); + + long keyValueBackupFuzzMilliseconds = mConstants.getKeyValueBackupFuzzMilliseconds(); + + assertThat(keyValueBackupFuzzMilliseconds) + .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS); + } + + /** + * Test passing in an invalid value type. {@link + * BackupManagerConstants#KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE} expects an integer, but we + * pass in a boolean. + */ + @Test + public void testGetConstant_whenSettingHasInvalidType_doesNotUpdateParamsOrThrow() { + boolean testValue = true; + final String invalidSettingType = + BackupManagerConstants.KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE + "=" + testValue; + putStringAndNotify(invalidSettingType); + + int keyValueBackupRequiredNetworkType = mConstants.getKeyValueBackupRequiredNetworkType(); + + assertThat(keyValueBackupRequiredNetworkType) + .isEqualTo(BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE); + } + + @Test + public void testGetConstants_afterSettingChange_updatesValues() { + long testKVInterval = + BackupManagerConstants.DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS * 2; + long testFullInterval = + BackupManagerConstants.DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS * 2; + final String intervalSetting = + BackupManagerConstants.KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS + + "=" + + testKVInterval + + "," + + BackupManagerConstants.FULL_BACKUP_INTERVAL_MILLISECONDS + + "=" + + testFullInterval; + putStringAndNotify(intervalSetting); + + long keyValueBackupIntervalMilliseconds = + mConstants.getKeyValueBackupIntervalMilliseconds(); + long fullBackupIntervalMilliseconds = mConstants.getFullBackupIntervalMilliseconds(); + + assertThat(keyValueBackupIntervalMilliseconds).isEqualTo(testKVInterval); + assertThat(fullBackupIntervalMilliseconds).isEqualTo(testFullInterval); + } + + @Test + public void testBackupNotificationReceivers_afterSetting_updatesAndParsesCorrectly() { + final String receiversSetting = + BackupManagerConstants.BACKUP_FINISHED_NOTIFICATION_RECEIVERS + + "=" + PACKAGE_NAME + ':' + ANOTHER_PACKAGE_NAME; - Settings.Secure.putString( - context.getContentResolver(), - Settings.Secure.BACKUP_MANAGER_CONSTANTS, - recieversSetting); - - final BackupManagerConstants constants = - new BackupManagerConstants(handler, context.getContentResolver()); + putStringAndNotify(receiversSetting); - assertThat(constants.getBackupFinishedNotificationReceivers()) + String[] backupFinishedNotificationReceivers = + mConstants.getBackupFinishedNotificationReceivers(); + assertThat(backupFinishedNotificationReceivers) .isEqualTo(new String[] {PACKAGE_NAME, ANOTHER_PACKAGE_NAME}); } + + /** + * Robolectric does not notify observers of changes to settings so we have to trigger it here. + * Currently, the mock of {@link Settings.Secure#putString(ContentResolver, String, String)} + * only stores the value. TODO: Implement properly in ShadowSettings. + */ + private void putStringAndNotify(String value) { + Settings.Secure.putString( + mContentResolver, Settings.Secure.BACKUP_MANAGER_CONSTANTS, value); + + // We pass null as the observer since notifyChange iterates over all available observers and + // we don't have access to the local observer. + mContentResolver.notifyChange( + Settings.Secure.getUriFor(Settings.Secure.BACKUP_MANAGER_CONSTANTS), + /*observer*/ null); + } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java index ac212ddc44e7..03e870acbaef 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java @@ -222,35 +222,4 @@ public class ActivityRecordTests extends ActivityTestsBase { verify(mService.mStackSupervisor, times(1)).canPlaceEntityOnDisplay(anyInt(), eq(expected), anyInt(), anyInt(), eq(record.info)); } - - @Test - public void testFinishingAfterDestroying() throws Exception { - assertFalse(mActivity.finishing); - mActivity.setState(DESTROYING, "testFinishingAfterDestroying"); - assertTrue(mActivity.isState(DESTROYING)); - assertTrue(mActivity.finishing); - } - - @Test - public void testFinishingAfterDestroyed() throws Exception { - assertFalse(mActivity.finishing); - mActivity.setState(DESTROYED, "testFinishingAfterDestroyed"); - assertTrue(mActivity.isState(DESTROYED)); - assertTrue(mActivity.finishing); - } - - @Test - public void testSetInvalidState() throws Exception { - mActivity.setState(DESTROYED, "testInvalidState"); - - boolean exceptionEncountered = false; - - try { - mActivity.setState(FINISHING, "testInvalidState"); - } catch (IllegalArgumentException e) { - exceptionEncountered = true; - } - - assertTrue(exceptionEncountered); - } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index bda68d16320f..f17bfa456c88 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -479,28 +479,6 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testSuppressMultipleDestroy() throws Exception { - final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); - final ClientLifecycleManager lifecycleManager = mock(ClientLifecycleManager.class); - final ProcessRecord app = r.app; - - // The mocked lifecycle manager must be set on the ActivityStackSupervisor's reference to - // the service rather than mService as mService is a spy and setting the value will not - // propagate as ActivityManagerService hands its own reference to the - // ActivityStackSupervisor during construction. - ((TestActivityManagerService) mSupervisor.mService).setLifecycleManager(lifecycleManager); - - mStack.destroyActivityLocked(r, true, "first invocation"); - verify(lifecycleManager, times(1)).scheduleTransaction(eq(app.thread), - eq(r.appToken), any(DestroyActivityItem.class)); - assertTrue(r.isState(DESTROYED, DESTROYING)); - - mStack.destroyActivityLocked(r, true, "second invocation"); - verify(lifecycleManager, times(1)).scheduleTransaction(eq(app.thread), - eq(r.appToken), any(DestroyActivityItem.class)); - } - - @Test public void testFinishDisabledPackageActivities() throws Exception { final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build(); final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build(); diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java index 24566fcf8f0d..376f5b193716 100644 --- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java +++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java @@ -17,6 +17,7 @@ package com.android.server.am; import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; @@ -24,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.view.Display.DEFAULT_DISPLAY; import static org.junit.Assert.assertFalse; @@ -74,7 +76,7 @@ import java.util.Random; import java.util.Set; /** - * runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java + * atest FrameworksServicesTests:RecentTasksTest */ @MediumTest @Presubmit @@ -145,7 +147,7 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks = (TestRecentTasks) mService.getRecentTasks(); mRecentTasks.loadParametersFromResources(mContext.getResources()); mHomeStack = mService.mStackSupervisor.getDefaultDisplay().createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); mStack = mService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); ((MyTestActivityStackSupervisor) mService.mStackSupervisor).setHomeStack(mHomeStack); @@ -236,7 +238,7 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testAddTasksMultipleTasks_expectNoTrim() throws Exception { + public void testAddTasksMultipleDocumentTasks_expectNoTrim() throws Exception { // Add same multiple-task document tasks does not trim the first tasks TaskRecord documentTask1 = createDocumentTask(".DocumentTask1", FLAG_ACTIVITY_MULTIPLE_TASK); @@ -252,6 +254,50 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test + public void testAddTasksMultipleTasks_expectRemovedNoTrim() throws Exception { + // Add multiple same-affinity non-document tasks, ensure that it removes the other task, + // but that it does not trim it + TaskRecord task1 = createTaskBuilder(".Task1") + .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) + .build(); + TaskRecord task2 = createTaskBuilder(".Task1") + .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) + .build(); + mRecentTasks.add(task1); + assertTrue(mCallbacksRecorder.added.size() == 1); + assertTrue(mCallbacksRecorder.added.contains(task1)); + assertTrue(mCallbacksRecorder.trimmed.isEmpty()); + assertTrue(mCallbacksRecorder.removed.isEmpty()); + mCallbacksRecorder.clear(); + mRecentTasks.add(task2); + assertTrue(mCallbacksRecorder.added.size() == 1); + assertTrue(mCallbacksRecorder.added.contains(task2)); + assertTrue(mCallbacksRecorder.trimmed.isEmpty()); + assertTrue(mCallbacksRecorder.removed.size() == 1); + assertTrue(mCallbacksRecorder.removed.contains(task1)); + } + + @Test + public void testAddTasksDifferentStacks_expectNoRemove() throws Exception { + // Adding the same task with different activity types should not trigger removal of the + // other task + TaskRecord task1 = createTaskBuilder(".Task1") + .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) + .setStack(mHomeStack).build(); + TaskRecord task2 = createTaskBuilder(".Task1") + .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) + .setStack(mStack).build(); + mRecentTasks.add(task1); + mRecentTasks.add(task2); + assertTrue(mCallbacksRecorder.added.size() == 2); + assertTrue(mCallbacksRecorder.added.contains(task1)); + assertTrue(mCallbacksRecorder.added.contains(task2)); + assertTrue(mCallbacksRecorder.trimmed.isEmpty()); + assertTrue(mCallbacksRecorder.removed.isEmpty()); + + } + + @Test public void testUsersTasks() throws Exception { mRecentTasks.setOnlyTestVisibleRange(); diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java index 86c83d6707b6..d37db20f05b7 100644 --- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java @@ -18,9 +18,14 @@ package com.android.server.backup.utils; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Process; import android.platform.test.annotations.Presubmit; @@ -30,6 +35,7 @@ import android.support.test.runner.AndroidJUnit4; import com.android.server.backup.BackupManagerService; import com.android.server.backup.testutils.PackageManagerStub; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,7 +51,14 @@ public class AppBackupUtilsTest { private static final Signature SIGNATURE_3 = generateSignature((byte) 3); private static final Signature SIGNATURE_4 = generateSignature((byte) 4); - private final PackageManagerStub mPackageManagerStub = new PackageManagerStub(); + private PackageManagerStub mPackageManagerStub; + private PackageManagerInternal mMockPackageManagerInternal; + + @Before + public void setUp() throws Exception { + mPackageManagerStub = new PackageManagerStub(); + mMockPackageManagerInternal = mock(PackageManagerInternal.class); + } @Test public void appIsEligibleForBackup_backupNotAllowed_returnsFalse() throws Exception { @@ -358,7 +371,8 @@ public class AppBackupUtilsTest { @Test public void signaturesMatch_targetIsNull_returnsFalse() throws Exception { - boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null); + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -366,10 +380,12 @@ public class AppBackupUtilsTest { @Test public void signaturesMatch_systemApplication_returnsTrue() throws Exception { PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; - boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo); + boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo, + mMockPackageManagerInternal); assertThat(result).isTrue(); } @@ -378,10 +394,12 @@ public class AppBackupUtilsTest { public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[] {SIGNATURE_1}; + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(null, packageInfo); + boolean result = AppBackupUtils.signaturesMatch(null, packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -390,10 +408,12 @@ public class AppBackupUtilsTest { public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[] {SIGNATURE_1}; + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo); + boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -404,11 +424,12 @@ public class AppBackupUtilsTest { signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[0]; + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[0][0]; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, - packageInfo); + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -418,11 +439,12 @@ public class AppBackupUtilsTest { signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = null; + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = null; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, - packageInfo); + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -431,10 +453,11 @@ public class AppBackupUtilsTest { public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = null; + packageInfo.signingCertificateHistory = null; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(null, packageInfo); + boolean result = AppBackupUtils.signaturesMatch(null, packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -443,10 +466,12 @@ public class AppBackupUtilsTest { public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[0]; + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[0][0]; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo); + boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -458,11 +483,15 @@ public class AppBackupUtilsTest { Signature signature3Copy = new Signature(SIGNATURE_3.toByteArray()); PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}; + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; packageInfo.applicationInfo = new ApplicationInfo(); boolean result = AppBackupUtils.signaturesMatch( - new Signature[]{signature3Copy, signature1Copy, signature2Copy}, packageInfo); + new Signature[] {signature3Copy, signature1Copy, signature2Copy}, packageInfo, + mMockPackageManagerInternal); assertThat(result).isTrue(); } @@ -473,11 +502,15 @@ public class AppBackupUtilsTest { Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray()); PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}; + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; packageInfo.applicationInfo = new ApplicationInfo(); boolean result = AppBackupUtils.signaturesMatch( - new Signature[]{signature2Copy, signature1Copy}, packageInfo); + new Signature[]{signature2Copy, signature1Copy}, packageInfo, + mMockPackageManagerInternal); assertThat(result).isTrue(); } @@ -488,11 +521,15 @@ public class AppBackupUtilsTest { Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray()); PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[]{signature1Copy, signature2Copy}; + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] { + {signature1Copy, signature2Copy} + }; packageInfo.applicationInfo = new ApplicationInfo(); boolean result = AppBackupUtils.signaturesMatch( - new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo); + new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -503,11 +540,77 @@ public class AppBackupUtilsTest { Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray()); PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}; + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; packageInfo.applicationInfo = new ApplicationInfo(); boolean result = AppBackupUtils.signaturesMatch( - new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo); + new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue() + throws Exception { + Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray()); + + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy, + packageInfo.packageName); + + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy}, + packageInfo, mMockPackageManagerInternal); + + assertThat(result).isTrue(); + } + + @Test + public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue() + throws Exception { + Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray()); + + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + // we know signature1Copy is in history, and we want to assume it has + // SigningDetails.CertCapabilities.INSTALLED_DATA capability + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy, + packageInfo.packageName); + + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy}, + packageInfo, mMockPackageManagerInternal); + + assertThat(result).isTrue(); + } + + @Test + public void + signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse() + throws Exception { + Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray()); + + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + // we know signature1Copy is in history, but we want to assume it does not have + // SigningDetails.CertCapabilities.INSTALLED_DATA capability + doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy, + packageInfo.packageName); + + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy}, + packageInfo, mMockPackageManagerInternal); assertThat(result).isFalse(); } diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java index 0cdf04bda2d0..5f052ceb2e26 100644 --- a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java @@ -28,6 +28,9 @@ import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BA import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; @@ -37,6 +40,7 @@ import android.app.backup.IBackupManagerMonitor; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Bundle; import android.os.Process; @@ -79,6 +83,7 @@ public class TarBackupReaderTest { @Mock private BytesReadListener mBytesReadListenerMock; @Mock private IBackupManagerMonitor mBackupManagerMonitorMock; + @Mock private PackageManagerInternal mMockPackageManagerInternal; private final PackageManagerStub mPackageManagerStub = new PackageManagerStub(); private Context mContext; @@ -139,7 +144,8 @@ public class TarBackupReaderTest { Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures( fileMetadata); RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( - mPackageManagerStub, false /* allowApks */, fileMetadata, signatures); + mPackageManagerStub, false /* allowApks */, fileMetadata, signatures, + mMockPackageManagerInternal); assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE); assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME); @@ -152,7 +158,8 @@ public class TarBackupReaderTest { signatures = tarBackupReader.readAppManifestAndReturnSignatures( fileMetadata); restorePolicy = tarBackupReader.chooseRestorePolicy( - mPackageManagerStub, false /* allowApks */, fileMetadata, signatures); + mPackageManagerStub, false /* allowApks */, fileMetadata, signatures, + mMockPackageManagerInternal); assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE); assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME); @@ -214,7 +221,8 @@ public class TarBackupReaderTest { mBytesReadListenerMock, mBackupManagerMonitorMock); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - true /* allowApks */, new FileMetadata(), null /* signatures */); + true /* allowApks */, new FileMetadata(), null /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); verifyZeroInteractions(mBackupManagerMonitorMock); @@ -234,7 +242,8 @@ public class TarBackupReaderTest { PackageManagerStub.sPackageInfo = null; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - true /* allowApks */, info, new Signature[0] /* signatures */); + true /* allowApks */, info, new Signature[0] /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK); ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -258,7 +267,8 @@ public class TarBackupReaderTest { PackageManagerStub.sPackageInfo = null; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - true /* allowApks */, info, new Signature[0] /* signatures */); + true /* allowApks */, info, new Signature[0] /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK); ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -283,7 +293,8 @@ public class TarBackupReaderTest { PackageManagerStub.sPackageInfo = null; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */); + false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -307,7 +318,8 @@ public class TarBackupReaderTest { PackageManagerStub.sPackageInfo = packageInfo; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */); + false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -333,7 +345,8 @@ public class TarBackupReaderTest { PackageManagerStub.sPackageInfo = packageInfo; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */); + false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -358,11 +371,11 @@ public class TarBackupReaderTest { packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; packageInfo.applicationInfo.backupAgentName = null; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_2}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_2}}; PackageManagerStub.sPackageInfo = packageInfo; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), signatures); + false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -383,16 +396,19 @@ public class TarBackupReaderTest { Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1}; PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP | ApplicationInfo.FLAG_RESTORE_ANY_VERSION; packageInfo.applicationInfo.uid = Process.SYSTEM_UID; packageInfo.applicationInfo.backupAgentName = "backup.agent"; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}}; PackageManagerStub.sPackageInfo = packageInfo; + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), signatures); + false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT); ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -412,16 +428,19 @@ public class TarBackupReaderTest { Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1}; PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP | ApplicationInfo.FLAG_RESTORE_ANY_VERSION; packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; packageInfo.applicationInfo.backupAgentName = null; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}}; PackageManagerStub.sPackageInfo = packageInfo; + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), signatures); + false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT); ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -444,17 +463,20 @@ public class TarBackupReaderTest { info.version = 1; PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION; packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; packageInfo.applicationInfo.backupAgentName = null; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}}; packageInfo.versionCode = 2; PackageManagerStub.sPackageInfo = packageInfo; + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, info, signatures); + false /* allowApks */, info, signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT); ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -479,17 +501,20 @@ public class TarBackupReaderTest { info.hasApk = true; PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION; packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; packageInfo.applicationInfo.backupAgentName = null; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}}; packageInfo.versionCode = 1; PackageManagerStub.sPackageInfo = packageInfo; + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - true /* allowApks */, info, signatures); + true /* allowApks */, info, signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK); verifyNoMoreInteractions(mBackupManagerMonitorMock); @@ -510,17 +535,20 @@ public class TarBackupReaderTest { info.version = 2; PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION; packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; packageInfo.applicationInfo.backupAgentName = null; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}}; packageInfo.versionCode = 1; PackageManagerStub.sPackageInfo = packageInfo; + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, info, signatures); + false /* allowApks */, info, signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index 1211f00b1252..2f2afd71706c 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -44,6 +44,7 @@ import java.util.List; import static org.mockito.Matchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.mock; @SmallTest public class DisplayManagerServiceTest extends AndroidTestCase { @@ -123,7 +124,7 @@ public class DisplayManagerServiceTest extends AndroidTestCase { "Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */, uniqueId); - displayManager.performTraversalInTransactionFromWindowManagerInternal(); + displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); // flush the handler displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */); @@ -161,7 +162,7 @@ public class DisplayManagerServiceTest extends AndroidTestCase { "Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */, uniqueId); - displayManager.performTraversalInTransactionFromWindowManagerInternal(); + displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); // flush the handler displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index e40e3a42ee53..e9289e5cadf3 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -42,11 +42,13 @@ import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.security.keystore.recovery.KeyDerivationParams; import android.security.keystore.recovery.KeyChainSnapshot; +import android.security.keystore.recovery.RecoveryController; import android.security.keystore.recovery.WrappedApplicationKey; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.util.Log; import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb; import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage; @@ -516,6 +518,34 @@ public class KeySyncTaskTest { recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID2); } + @Test + public void run_customLockScreen_RecoveryStatusFailure() throws Exception { + mKeySyncTask = new KeySyncTask( + mRecoverableKeyStoreDb, + mRecoverySnapshotStorage, + mSnapshotListenersStorage, + TEST_USER_ID, + /*credentialType=*/ 3, + "12345", + /*credentialUpdated=*/ false, + mPlatformKeyManager); + + addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS); + + int status = + mRecoverableKeyStoreDb + .getStatusForAllKeys(TEST_RECOVERY_AGENT_UID) + .get(TEST_APP_KEY_ALIAS); + assertEquals(RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS, status); + + mKeySyncTask.run(); + + status = mRecoverableKeyStoreDb + .getStatusForAllKeys(TEST_RECOVERY_AGENT_UID) + .get(TEST_APP_KEY_ALIAS); + assertEquals(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE, status); + } + private SecretKey addApplicationKey(int userId, int recoveryAgentUid, String alias) throws Exception{ SecretKey applicationKey = generateKey(); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java index dfb2dbf884f0..8b01d972f7e5 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java @@ -342,6 +342,30 @@ public class RecoverableKeyStoreDbTest { } @Test + public void testInvalidateKeysForUserIdOnCustomScreenLock() { + int userId = 12; + int uid = 1009; + int generationId = 6; + int status = 120; + int status2 = 121; + String alias = "test"; + byte[] nonce = getUtf8Bytes("nonce"); + byte[] keyMaterial = getUtf8Bytes("keymaterial"); + WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status); + mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey); + + WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias); + assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status); + + mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status2); + mRecoverableKeyStoreDb.invalidateKeysForUserIdOnCustomScreenLock(userId); + + retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias); + assertThat(retrievedKey.getRecoveryStatus()) + .isEqualTo(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE); + } + + @Test public void setRecoveryServicePublicKey_replaceOldKey() throws Exception { int userId = 12; int uid = 10009; diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 51d27fe016f0..197475032ea8 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -1015,7 +1015,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { | ApplicationInfo.FLAG_ALLOW_BACKUP; pi.versionCode = version; pi.applicationInfo.versionCode = version; - pi.signatures = genSignatures(signatures); + pi.signatures = null; + pi.signingCertificateHistory = new Signature[][] {genSignatures(signatures)}; return pi; } @@ -1103,7 +1104,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { !mDisabledPackages.contains(PackageWithUser.of(userId, packageName)); if (getSignatures) { - ret.signatures = pi.signatures; + ret.signatures = null; + ret.signingCertificateHistory = pi.signingCertificateHistory; } return ret; diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 845e05d28465..7815004c18f9 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -62,6 +62,7 @@ import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -3987,6 +3988,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { if (!nowBackupAllowed) { pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP; } + + doReturn(expected != DISABLED_REASON_SIGNATURE_MISMATCH).when( + mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), anyString()); + assertEquals(expected, spi.canRestoreTo(mService, pi, anyVersionOk)); } @@ -4959,6 +4964,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3))); assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1))); + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), + anyString()); + installPackage(USER_0, CALLING_PACKAGE_1); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertWith(getCallerVisibleShortcuts()) @@ -5151,6 +5159,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { protected void checkBackupAndRestore_publisherNotRestored( int package1DisabledReason) { + doReturn(package1DisabledReason != ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH).when( + mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), + eq(CALLING_PACKAGE_1)); + installPackage(USER_0, CALLING_PACKAGE_1); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); @@ -5159,6 +5171,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0) .getPackageInfo().isShadow()); + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe( + any(byte[].class), anyString()); installPackage(USER_0, CALLING_PACKAGE_2); runWithCaller(CALLING_PACKAGE_2, USER_0, () -> { @@ -5276,7 +5290,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature - checkBackupAndRestore_launcherNotRestored(); + checkBackupAndRestore_launcherNotRestored(true); } public void testBackupAndRestore_launcherNoLongerBackupTarget() { @@ -5285,10 +5299,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { updatePackageInfo(LAUNCHER_1, pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP); - checkBackupAndRestore_launcherNotRestored(); + checkBackupAndRestore_launcherNotRestored(false); } - protected void checkBackupAndRestore_launcherNotRestored() { + protected void checkBackupAndRestore_launcherNotRestored(boolean differentSignatures) { + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe( + any(byte[].class), anyString()); + installPackage(USER_0, CALLING_PACKAGE_1); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); @@ -5307,6 +5324,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "s1", "s2", "s3"); }); + doReturn(!differentSignatures).when(mMockPackageManagerInternal).isDataRestoreSafe( + any(byte[].class), eq(LAUNCHER_1)); + // Now we try to restore launcher 1. Then we realize it's not restorable, so L1 has no pinned // shortcuts. installPackage(USER_0, LAUNCHER_1); @@ -5333,6 +5353,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "s2"); }); + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe( + any(byte[].class), anyString()); + installPackage(USER_0, LAUNCHER_2); runWithCaller(LAUNCHER_2, USER_0, () -> { assertShortcutIds(assertAllPinned( @@ -5388,6 +5411,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } protected void checkBackupAndRestore_publisherAndLauncherNotRestored() { + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), + anyString()); installPackage(USER_0, CALLING_PACKAGE_1); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertEquals(0, mManager.getDynamicShortcuts().size()); @@ -5501,6 +5526,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3))); assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1))); + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), + anyString()); + installPackage(USER_0, CALLING_PACKAGE_1); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertWith(getCallerVisibleShortcuts()) @@ -5586,6 +5614,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .areAllDisabled(); }); + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe( + any(byte[].class), anyString()); backupAndRestore(); // When re-installing the app, the manifest shortcut should be re-published. @@ -5695,6 +5725,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { .haveIds("s1", "ms1"); }); + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), + anyString()); // Backup and *without restarting the service, just call applyRestore()*. { int prevUid = mInjectedCallingUid; @@ -5768,6 +5800,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { list("ms1", "ms2", "ms3", "ms4", "s1", "s2"), HANDLE_USER_0); }); + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe( + any(byte[].class), anyString()); + backupAndRestore(); // Lower the version and remove the manifest shortcuts. @@ -5994,6 +6029,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "22222"); addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "11111"); + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe( + any(byte[].class), anyString()); + runWithSystemUid(() -> mService.applyRestore(payload, USER_0)); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java index 29c98dcf5228..cd7feea08caa 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java @@ -76,11 +76,13 @@ public class ShortcutManagerTest5 extends BaseShortcutManagerTest { mMyPackage, mMyUserId, /*signature*/ false); assertEquals(mMyPackage, pi.packageName); assertNull(pi.signatures); + assertNull(pi.signingCertificateHistory); pi = mShortcutService.getPackageInfo( mMyPackage, mMyUserId, /*signature*/ true); assertEquals(mMyPackage, pi.packageName); - assertNotNull(pi.signatures); + assertNull(pi.signatures); + assertNotNull(pi.signingCertificateHistory); pi = mShortcutService.getPackageInfo( "no.such.package", mMyUserId, /*signature*/ true); diff --git a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java index c016e6104755..1ac7cb86f867 100644 --- a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java @@ -15,73 +15,309 @@ */ package com.android.server.pm.backup; +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser.Package; import android.content.pm.Signature; -import android.test.AndroidTestCase; import android.test.MoreAsserts; -import android.test.suitebuilder.annotation.SmallTest; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import com.android.server.backup.BackupUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.util.ArrayList; import java.util.Arrays; @SmallTest -public class BackupUtilsTest extends AndroidTestCase { +@Presubmit +@RunWith(AndroidJUnit4.class) +public class BackupUtilsTest { + + private static final Signature SIGNATURE_1 = generateSignature((byte) 1); + private static final Signature SIGNATURE_2 = generateSignature((byte) 2); + private static final Signature SIGNATURE_3 = generateSignature((byte) 3); + private static final Signature SIGNATURE_4 = generateSignature((byte) 4); + private static final byte[] SIGNATURE_HASH_1 = BackupUtils.hashSignature(SIGNATURE_1); + private static final byte[] SIGNATURE_HASH_2 = BackupUtils.hashSignature(SIGNATURE_2); + private static final byte[] SIGNATURE_HASH_3 = BackupUtils.hashSignature(SIGNATURE_3); + private static final byte[] SIGNATURE_HASH_4 = BackupUtils.hashSignature(SIGNATURE_4); - private Signature[] genSignatures(String... signatures) { - final Signature[] sigs = new Signature[signatures.length]; - for (int i = 0; i < signatures.length; i++){ - sigs[i] = new Signature(signatures[i].getBytes()); - } - return sigs; + private PackageManagerInternal mMockPackageManagerInternal; + + @Before + public void setUp() throws Exception { + mMockPackageManagerInternal = mock(PackageManagerInternal.class); } - private PackageInfo genPackage(String... signatures) { - final PackageInfo pi = new PackageInfo(); - pi.packageName = "package"; - pi.applicationInfo = new ApplicationInfo(); - pi.signatures = genSignatures(signatures); + @Test + public void signaturesMatch_targetIsNull_returnsFalse() throws Exception { + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, null, + mMockPackageManagerInternal); - return pi; + assertThat(result).isFalse(); } - public void testSignaturesMatch() { - final ArrayList<byte[]> stored1 = BackupUtils.hashSignatureArray(Arrays.asList( - "abc".getBytes())); - final ArrayList<byte[]> stored2 = BackupUtils.hashSignatureArray(Arrays.asList( - "abc".getBytes(), "def".getBytes())); + @Test + public void signaturesMatch_systemApplication_returnsTrue() throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.applicationInfo = new ApplicationInfo(); + packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; + + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isTrue(); + } + + @Test + public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + boolean result = BackupUtils.signaturesMatch(null, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + + @Test + public void + signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[0][0]; + packageInfo.applicationInfo = new ApplicationInfo(); + + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void + signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = null; + packageInfo.applicationInfo = new ApplicationInfo(); + + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = null; + packageInfo.applicationInfo = new ApplicationInfo(); + + boolean result = BackupUtils.signaturesMatch(null, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[0][0]; + packageInfo.applicationInfo = new ApplicationInfo(); + + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_equalSignatures_returnsTrue() throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; + packageInfo.applicationInfo = new ApplicationInfo(); - PackageInfo pi; + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + storedSigHashes.add(SIGNATURE_HASH_2); + storedSigHashes.add(SIGNATURE_HASH_3); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); - // False for null package. - assertFalse(BackupUtils.signaturesMatch(stored1, null)); + assertThat(result).isTrue(); + } - // If it's a system app, signatures don't matter. - pi = genPackage("xyz"); - pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; - assertTrue(BackupUtils.signaturesMatch(stored1, pi)); + @Test + public void signaturesMatch_extraSignatureInTarget_returnsTrue() throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; + packageInfo.applicationInfo = new ApplicationInfo(); - // Non system apps. - assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc"))); + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + storedSigHashes.add(SIGNATURE_HASH_2); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); - // Superset is okay. - assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc", "xyz"))); - assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "abc"))); + assertThat(result).isTrue(); + } - assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz"))); - assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "def"))); + @Test + public void signaturesMatch_extraSignatureInStored_returnsFalse() throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1, SIGNATURE_2}}; + packageInfo.applicationInfo = new ApplicationInfo(); - assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("def", "abc"))); - assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("x", "def", "abc", "y"))); + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + storedSigHashes.add(SIGNATURE_HASH_2); + storedSigHashes.add(SIGNATURE_HASH_3); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); - // Subset is not okay. - assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("abc"))); - assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("def"))); + assertThat(result).isFalse(); } + @Test + public void signaturesMatch_oneNonMatchingSignature_returnsFalse() throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; + packageInfo.applicationInfo = new ApplicationInfo(); + + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + storedSigHashes.add(SIGNATURE_HASH_2); + storedSigHashes.add(SIGNATURE_HASH_4); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1, + packageInfo.packageName); + + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isTrue(); + } + + @Test + public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + // we know SIGNATURE_1 is in history, and we want to assume it has + // SigningDetails.CertCapabilities.INSTALLED_DATA capability + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1, + packageInfo.packageName); + + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isTrue(); + } + + @Test + public void + signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + // we know SIGNATURE_1 is in history, but we want to assume it does not have + // SigningDetails.CertCapabilities.INSTALLED_DATA capability + doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1, + packageInfo.packageName); + + ArrayList<byte[]> storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test public void testHashSignature() { final byte[] sig1 = "abc".getBytes(); final byte[] sig2 = "def".getBytes(); @@ -115,4 +351,10 @@ public class BackupUtilsTest extends AndroidTestCase { MoreAsserts.assertEquals(hash2a, listA.get(1)); MoreAsserts.assertEquals(hash2a, listB.get(1)); } + + private static Signature generateSignature(byte i) { + byte[] signatureBytes = new byte[256]; + signatureBytes[0] = i; + return new Signature(signatureBytes); + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java index 76e4e895278e..e0645b1f4bfb 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java @@ -20,11 +20,9 @@ import android.support.test.filters.FlakyTest; import org.junit.Test; import android.platform.test.annotations.Presubmit; -import android.platform.test.annotations.SecurityTest; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import android.view.WindowManager; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -36,13 +34,12 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; -import java.util.function.Consumer; +import com.android.server.wm.WindowTestUtils.TestTaskWindowContainerController; /** * Test class for {@link AppWindowContainerController}. * - * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests + * atest FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests */ @SmallTest @Presubmit @@ -176,6 +173,33 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { } @Test + public void testTryTransferStartingWindowFromHiddenAboveToken() throws Exception { + + // Add two tasks on top of each other. + TestTaskWindowContainerController taskController = + new WindowTestUtils.TestTaskWindowContainerController(this); + final WindowTestUtils.TestAppWindowContainerController controllerTop = + createAppWindowController(taskController); + final WindowTestUtils.TestAppWindowContainerController controllerBottom = + createAppWindowController(taskController); + + // Add a starting window. + controllerTop.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), + android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, + false, false); + waitUntilHandlersIdle(); + + // Make the top one invisible, and try transfering the starting window from the top to the + // bottom one. + controllerTop.setVisibility(false, false); + controllerBottom.mContainer.transferStartingWindowFromHiddenAboveTokenIfNeeded(); + + // Assert that the bottom window now has the starting window. + assertNoStartingWindow(controllerTop.getAppWindowToken(mDisplayContent)); + assertHasStartingWindow(controllerBottom.getAppWindowToken(mDisplayContent)); + } + + @Test public void testReparent() throws Exception { final StackWindowController stackController = createStackControllerOnDisplay(mDisplayContent); diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index 6784e302a5c4..6d9167fda585 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -656,4 +656,8 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void requestUserActivityNotification() { } + + @Override + public void onLockTaskStateChangedLw(int lockTaskState) { + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java index cdcb949b2a3c..56b7d9f40ec0 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java @@ -38,7 +38,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; -import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static org.junit.Assert.assertEquals; @@ -288,6 +287,16 @@ public class WindowStateTests extends WindowTestsBase { app.mToken.setHidden(false); app.mAttrs.alpha = 0.0f; assertFalse(app.canAffectSystemUiFlags()); + + } + + @Test + public void testCanAffectSystemUiFlags_disallow() throws Exception { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + app.mToken.setHidden(false); + assertTrue(app.canAffectSystemUiFlags()); + app.getTask().setCanAffectSystemUiFlags(false); + assertFalse(app.canAffectSystemUiFlags()); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 9008803c2c2f..be58fd2c66dd 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.AppOpsManager; import android.app.NotificationManager; import android.content.ComponentName; import android.content.ContentResolver; @@ -160,6 +161,26 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + public void testTotalSilence() { + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; + mZenModeHelperSpy.applyRestrictions(); + + // Total silence will silence alarms, media and system noises (but not vibrations) + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_ALARM); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_MEDIA); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_GAME); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, + AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_VIBRATE); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, + AudioAttributes.USAGE_UNKNOWN); + } + + @Test public void testAlarmsOnly_alarmMediaMuteNotApplied() { mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_ALARMS; mZenModeHelperSpy.mConfig.allowAlarms = false; @@ -179,9 +200,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, AudioAttributes.USAGE_GAME); - // Alarms only will silence system noises + // Alarms only will silence system noises (but not vibrations) verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, - AudioAttributes.USAGE_ASSISTANCE_SONIFICATION); + AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO); verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, AudioAttributes.USAGE_UNKNOWN); } @@ -228,6 +249,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testZenAllCannotBypass() { // Only audio attributes with SUPPRESIBLE_NEVER can bypass + // with special case USAGE_ASSISTANCE_SONIFICATION mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.allowAlarms = false; mZenModeHelperSpy.mConfig.allowMedia = false; @@ -247,9 +269,17 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.applyRestrictions(); for (int usage : AudioAttributes.SDK_USAGES) { - boolean shouldMute = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage) - != AudioAttributes.SUPPRESSIBLE_NEVER; - verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(shouldMute, usage); + if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) { + // only mute audio, not vibrations + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, usage, + AppOpsManager.OP_PLAY_AUDIO); + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, usage, + AppOpsManager.OP_VIBRATE); + } else { + boolean shouldMute = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage) + != AudioAttributes.SUPPRESSIBLE_NEVER; + verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(shouldMute, usage); + } } } diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java index 1052e8f377a7..3c4e333b6be9 100644 --- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java +++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java @@ -1,7 +1,5 @@ package com.android.server.slice; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; - import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -12,23 +10,18 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.slice.ISliceListener; -import android.app.slice.Slice; import android.app.slice.SliceProvider; import android.app.slice.SliceSpec; import android.content.ContentProvider; -import android.content.Context; import android.content.IContentProvider; import android.net.Uri; import android.os.Binder; -import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.IBinder.DeathRecipient; @@ -83,7 +76,7 @@ public class PinnedSliceStateTest extends UiServiceTestCase { mIContentProvider = mock(IContentProvider.class); when(mContentProvider.getIContentProvider()).thenReturn(mIContentProvider); mContext.getContentResolver().addProvider(AUTH, mContentProvider); - mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI); + mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI, "pkg"); } @Test @@ -164,4 +157,4 @@ public class PinnedSliceStateTest extends UiServiceTestCase { verify(mSliceService).removePinnedSlice(eq(TEST_URI)); assertFalse(mPinnedSliceManager.hasPinOrListener()); } -}
\ No newline at end of file +} diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java index 6fc300959144..4f446a9afb98 100644 --- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java @@ -18,6 +18,7 @@ import static android.content.ContentProvider.maybeAddUserId; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -28,7 +29,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AppOpsManager; -import android.app.slice.ISliceListener; import android.app.slice.SliceSpec; import android.content.pm.PackageManagerInternal; import android.net.Uri; @@ -71,7 +71,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase { mService = spy(new SliceManagerService(mContext, TestableLooper.get(this).getLooper())); mCreatedSliceState = mock(PinnedSliceState.class); - doReturn(mCreatedSliceState).when(mService).createPinnedSlice(eq(TEST_URI)); + doReturn(mCreatedSliceState).when(mService).createPinnedSlice(eq(TEST_URI), anyString()); } @After @@ -85,7 +85,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase { mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken); mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken); - verify(mService, times(1)).createPinnedSlice(eq(TEST_URI)); + verify(mService, times(1)).createPinnedSlice(eq(TEST_URI), eq("pkg")); } @Test diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java new file mode 100644 index 000000000000..5d2c225f28ec --- /dev/null +++ b/telephony/java/android/telephony/AccessNetworkUtils.java @@ -0,0 +1,167 @@ +package android.telephony; + +import static android.telephony.ServiceState.DUPLEX_MODE_FDD; +import static android.telephony.ServiceState.DUPLEX_MODE_TDD; +import static android.telephony.ServiceState.DUPLEX_MODE_UNKNOWN; + +import android.telephony.AccessNetworkConstants.EutranBand; +import android.telephony.ServiceState.DuplexMode; + + +/** + * Utilities to map between radio constants. + * + * @hide + */ +public class AccessNetworkUtils { + + // do not instantiate + private AccessNetworkUtils() {} + + public static final int INVALID_BAND = -1; + + /** + * Gets the duplex mode for the given EUTRAN operating band. + * + * <p>See 3GPP 36.101 sec 5.5-1 for calculation + * + * @param band The EUTRAN band number + * @return The duplex mode of the given EUTRAN band + */ + @DuplexMode + public static int getDuplexModeForEutranBand(int band) { + if (band == INVALID_BAND) { + return DUPLEX_MODE_UNKNOWN; + } + + if (band >= EutranBand.BAND_68) { + return DUPLEX_MODE_UNKNOWN; + } else if (band >= EutranBand.BAND_65) { + return DUPLEX_MODE_FDD; + } else if (band >= EutranBand.BAND_47) { + return DUPLEX_MODE_UNKNOWN; + } else if (band >= EutranBand.BAND_33) { + return DUPLEX_MODE_TDD; + } else if (band >= EutranBand.BAND_1) { + return DUPLEX_MODE_FDD; + } + + return DUPLEX_MODE_UNKNOWN; + } + + /** + * Gets the EUTRAN Operating band for a given downlink EARFCN. + * + * <p>See 3GPP 36.101 sec 5.7.3-1 for calculation. + * + * @param earfcn The downlink EARFCN + * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists + */ + public static int getOperatingBandForEarfcn(int earfcn) { + if (earfcn > 67535) { + return INVALID_BAND; + } else if (earfcn >= 67366) { + return INVALID_BAND; // band 67 only for CarrierAgg + } else if (earfcn >= 66436) { + return EutranBand.BAND_66; + } else if (earfcn >= 65536) { + return EutranBand.BAND_65; + } else if (earfcn > 54339) { + return INVALID_BAND; + } else if (earfcn >= 46790 /* inferred from the end range of BAND_45 */) { + return EutranBand.BAND_46; + } else if (earfcn >= 46590) { + return EutranBand.BAND_45; + } else if (earfcn >= 45590) { + return EutranBand.BAND_44; + } else if (earfcn >= 43590) { + return EutranBand.BAND_43; + } else if (earfcn >= 41590) { + return EutranBand.BAND_42; + } else if (earfcn >= 39650) { + return EutranBand.BAND_41; + } else if (earfcn >= 38650) { + return EutranBand.BAND_40; + } else if (earfcn >= 38250) { + return EutranBand.BAND_39; + } else if (earfcn >= 37750) { + return EutranBand.BAND_38; + } else if (earfcn >= 37550) { + return EutranBand.BAND_37; + } else if (earfcn >= 36950) { + return EutranBand.BAND_36; + } else if (earfcn >= 36350) { + return EutranBand.BAND_35; + } else if (earfcn >= 36200) { + return EutranBand.BAND_34; + } else if (earfcn >= 36000) { + return EutranBand.BAND_33; + } else if (earfcn > 10359) { + return INVALID_BAND; + } else if (earfcn >= 9920) { + return INVALID_BAND; // band 32 only for CarrierAgg + } else if (earfcn >= 9870) { + return EutranBand.BAND_31; + } else if (earfcn >= 9770) { + return EutranBand.BAND_30; + } else if (earfcn >= 9660) { + return INVALID_BAND; // band 29 only for CarrierAgg + } else if (earfcn >= 9210) { + return EutranBand.BAND_28; + } else if (earfcn >= 9040) { + return EutranBand.BAND_27; + } else if (earfcn >= 8690) { + return EutranBand.BAND_26; + } else if (earfcn >= 8040) { + return EutranBand.BAND_25; + } else if (earfcn >= 7700) { + return EutranBand.BAND_24; + } else if (earfcn >= 7500) { + return EutranBand.BAND_23; + } else if (earfcn >= 6600) { + return EutranBand.BAND_22; + } else if (earfcn >= 6450) { + return EutranBand.BAND_21; + } else if (earfcn >= 6150) { + return EutranBand.BAND_20; + } else if (earfcn >= 6000) { + return EutranBand.BAND_19; + } else if (earfcn >= 5850) { + return EutranBand.BAND_18; + } else if (earfcn >= 5730) { + return EutranBand.BAND_17; + } else if (earfcn > 5379) { + return INVALID_BAND; + } else if (earfcn >= 5280) { + return EutranBand.BAND_14; + } else if (earfcn >= 5180) { + return EutranBand.BAND_13; + } else if (earfcn >= 5010) { + return EutranBand.BAND_12; + } else if (earfcn >= 4750) { + return EutranBand.BAND_11; + } else if (earfcn >= 4150) { + return EutranBand.BAND_10; + } else if (earfcn >= 3800) { + return EutranBand.BAND_9; + } else if (earfcn >= 3450) { + return EutranBand.BAND_8; + } else if (earfcn >= 2750) { + return EutranBand.BAND_7; + } else if (earfcn >= 2650) { + return EutranBand.BAND_6; + } else if (earfcn >= 2400) { + return EutranBand.BAND_5; + } else if (earfcn >= 1950) { + return EutranBand.BAND_4; + } else if (earfcn >= 1200) { + return EutranBand.BAND_3; + } else if (earfcn >= 600) { + return EutranBand.BAND_2; + } else if (earfcn >= 0) { + return EutranBand.BAND_1; + } + + return INVALID_BAND; + } +} diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index e092d52d91bc..08f8bb6494a0 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -68,6 +68,9 @@ public abstract class CellIdentity implements Parcelable { */ public static final int TYPE_TDSCDMA = 5; + /** @hide */ + public static final int INVALID_CHANNEL_NUMBER = -1; + // Log tag /** @hide */ protected final String mTag; @@ -125,6 +128,16 @@ public abstract class CellIdentity implements Parcelable { public @Type int getType() { return mType; } /** + * Returns the channel number of the cell identity. + * + * @hide + * @return The channel number, or {@link #INVALID_CHANNEL_NUMBER} if not implemented + */ + public int getChannelNumber() { + return INVALID_CHANNEL_NUMBER; + } + + /** * Used by child classes for parceling. * * @hide diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index d35eb60916f3..52944a8ac261 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -203,6 +203,11 @@ public final class CellIdentityGsm extends CellIdentity { return mAlphaShort; } + /** @hide */ + @Override + public int getChannelNumber() { + return mArfcn; + } /** * @deprecated Primary Scrambling Code is not applicable to GSM. diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index 2b8eb5f3cca6..37fb07521b0e 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -213,6 +213,12 @@ public final class CellIdentityLte extends CellIdentity { return mAlphaShort; } + /** @hide */ + @Override + public int getChannelNumber() { + return mEarfcn; + } + @Override public int hashCode() { return Objects.hash(mMccStr, mMncStr, mCi, mPci, mTac, mAlphaLong, mAlphaShort); diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java index a5fd7dd97941..affa0c15862d 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -206,6 +206,12 @@ public final class CellIdentityWcdma extends CellIdentity { return mUarfcn; } + /** @hide */ + @Override + public int getChannelNumber() { + return mUarfcn; + } + @Override public boolean equals(Object other) { if (this == other) { diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java index ce1b80c2c860..81a966b7de2f 100644 --- a/telephony/java/android/telephony/MbmsDownloadSession.java +++ b/telephony/java/android/telephony/MbmsDownloadSession.java @@ -131,6 +131,14 @@ public class MbmsDownloadSession implements AutoCloseable { */ public static final String DEFAULT_TOP_LEVEL_TEMP_DIRECTORY = "androidMbmsTempFileRoot"; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = {RESULT_SUCCESSFUL, RESULT_CANCELLED, RESULT_EXPIRED, RESULT_IO_ERROR, + RESULT_SERVICE_ID_NOT_DEFINED, RESULT_DOWNLOAD_FAILURE, RESULT_OUT_OF_STORAGE, + RESULT_FILE_ROOT_UNREACHABLE}, prefix = { "RESULT_" }) + public @interface DownloadResultCode{} + /** * Indicates that the download was successful. */ diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java index 7f43ee5f425c..073c313a61df 100644 --- a/telephony/java/android/telephony/NetworkScan.java +++ b/telephony/java/android/telephony/NetworkScan.java @@ -115,6 +115,8 @@ public class NetworkScan { telephony.stopNetworkScan(mSubId, mScanId); } catch (RemoteException ex) { Rlog.e(TAG, "stopNetworkScan RemoteException", ex); + } catch (RuntimeException ex) { + Rlog.e(TAG, "stopNetworkScan RuntimeException", ex); } } diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 82a7450945f7..a9c1cf6c7bc3 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -471,9 +471,13 @@ public class ServiceState implements Parcelable { */ @DuplexMode public int getDuplexMode() { - // TODO(b/72117602) determine duplex mode from channel number, using 3GPP 36.101 sections - // 5.7.3-1 and 5.5-1 - return DUPLEX_MODE_UNKNOWN; + // only support LTE duplex mode + if (!isLte(mRilDataRadioTechnology)) { + return DUPLEX_MODE_UNKNOWN; + } + + int band = AccessNetworkUtils.getOperatingBandForEarfcn(mChannelNumber); + return AccessNetworkUtils.getDuplexModeForEutranBand(band); } /** @@ -891,6 +895,7 @@ public class ServiceState implements Parcelable { .append(", mDataRegState=").append(mDataRegState) .append("(" + rilServiceStateToString(mDataRegState) + ")") .append(", mChannelNumber=").append(mChannelNumber) + .append(", duplexMode()=").append(getDuplexMode()) .append(", mCellBandwidths=").append(Arrays.toString(mCellBandwidths)) .append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType)) .append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType)) diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 22795b194e46..4a0027b7fd77 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -5183,7 +5183,7 @@ public class TelephonyManager { ITelephony telephony = getITelephony(); if (telephony == null) return null; - return telephony.getForbiddenPlmns(subId, appType); + return telephony.getForbiddenPlmns(subId, appType, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -5351,6 +5351,23 @@ public class TelephonyManager { } /** + * @return true if the IMS resolver is busy resolving a binding and should not be considered + * available, false if the IMS resolver is idle. + * @hide + */ + public boolean isResolvingImsBinding() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.isResolvingImsBinding(); + } + } catch (RemoteException e) { + Rlog.e(TAG, "isResolvingImsBinding, RemoteException: " + e.getMessage()); + } + return false; + } + + /** * Set IMS registration state * * @param Registration state diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java index 946cecfa261c..99e2db883e52 100644 --- a/telephony/java/android/telephony/TelephonyScanManager.java +++ b/telephony/java/android/telephony/TelephonyScanManager.java @@ -145,7 +145,8 @@ public final class TelephonyScanManager { break; case CALLBACK_SCAN_ERROR: try { - executor.execute(() -> callback.onError(message.arg1)); + final int errorCode = message.arg1; + executor.execute(() -> callback.onError(errorCode)); } catch (Exception e) { Rlog.e(TAG, "Exception in networkscan callback onError", e); } diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java index 0c17147ca3fa..125161d62373 100644 --- a/telephony/java/android/telephony/UiccSlotInfo.java +++ b/telephony/java/android/telephony/UiccSlotInfo.java @@ -60,6 +60,7 @@ public class UiccSlotInfo implements Parcelable { private final String mCardId; private final @CardStateInfo int mCardStateInfo; private final int mLogicalSlotIdx; + private final boolean mIsExtendedApduSupported; public static final Creator<UiccSlotInfo> CREATOR = new Creator<UiccSlotInfo>() { @Override @@ -79,6 +80,7 @@ public class UiccSlotInfo implements Parcelable { mCardId = in.readString(); mCardStateInfo = in.readInt(); mLogicalSlotIdx = in.readInt(); + mIsExtendedApduSupported = in.readByte() != 0; } @Override @@ -88,6 +90,7 @@ public class UiccSlotInfo implements Parcelable { dest.writeString(mCardId); dest.writeInt(mCardStateInfo); dest.writeInt(mLogicalSlotIdx); + dest.writeByte((byte) (mIsExtendedApduSupported ? 1 : 0)); } @Override @@ -96,12 +99,13 @@ public class UiccSlotInfo implements Parcelable { } public UiccSlotInfo(boolean isActive, boolean isEuicc, String cardId, - @CardStateInfo int cardStateInfo, int logicalSlotIdx) { + @CardStateInfo int cardStateInfo, int logicalSlotIdx, boolean isExtendedApduSupported) { this.mIsActive = isActive; this.mIsEuicc = isEuicc; this.mCardId = cardId; this.mCardStateInfo = cardStateInfo; this.mLogicalSlotIdx = logicalSlotIdx; + this.mIsExtendedApduSupported = isExtendedApduSupported; } public boolean getIsActive() { @@ -125,6 +129,13 @@ public class UiccSlotInfo implements Parcelable { return mLogicalSlotIdx; } + /** + * @return {@code true} if this slot supports extended APDU from ATR, {@code false} otherwise. + */ + public boolean getIsExtendedApduSupported() { + return mIsExtendedApduSupported; + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -139,7 +150,8 @@ public class UiccSlotInfo implements Parcelable { && (mIsEuicc == that.mIsEuicc) && (mCardId == that.mCardId) && (mCardStateInfo == that.mCardStateInfo) - && (mLogicalSlotIdx == that.mLogicalSlotIdx); + && (mLogicalSlotIdx == that.mLogicalSlotIdx) + && (mIsExtendedApduSupported == that.mIsExtendedApduSupported); } @Override @@ -150,6 +162,7 @@ public class UiccSlotInfo implements Parcelable { result = 31 * result + Objects.hashCode(mCardId); result = 31 * result + mCardStateInfo; result = 31 * result + mLogicalSlotIdx; + result = 31 * result + (mIsExtendedApduSupported ? 1 : 0); return result; } @@ -165,6 +178,8 @@ public class UiccSlotInfo implements Parcelable { + mCardStateInfo + ", phoneId=" + mLogicalSlotIdx + + ", mIsExtendedApduSupported=" + + mIsExtendedApduSupported + ")"; } } diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index 2748cb5470bf..c008711ff236 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -161,11 +161,6 @@ public class ImsService extends Service { } @Override - public void notifyImsFeatureReady(int slotId, int featureType) { - ImsService.this.notifyImsFeatureReady(slotId, featureType); - } - - @Override public IImsConfig getConfig(int slotId) { ImsConfigImplBase c = ImsService.this.getConfig(slotId); return c != null ? c.getIImsConfig() : null; @@ -274,25 +269,6 @@ public class ImsService extends Service { } } - private void notifyImsFeatureReady(int slotId, int featureType) { - synchronized (mFeaturesBySlot) { - // get ImsFeature associated with the slot/feature - SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); - if (features == null) { - Log.w(LOG_TAG, "Can not notify ImsFeature ready. No ImsFeatures exist on " + - "slot " + slotId); - return; - } - ImsFeature f = features.get(featureType); - if (f == null) { - Log.w(LOG_TAG, "Can not notify ImsFeature ready. No feature with type " - + featureType + " exists on slot " + slotId); - return; - } - f.onFeatureReady(); - } - } - /** * When called, provide the {@link ImsFeatureConfiguration} that this {@link ImsService} * currently supports. This will trigger the framework to set up the {@link ImsFeature}s that diff --git a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl index 86f8606ac39f..c7da681b86a3 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl @@ -36,8 +36,6 @@ interface IImsServiceController { ImsFeatureConfiguration querySupportedImsFeatures(); // Synchronous call to ensure the ImsService is ready before continuing with feature creation. void notifyImsServiceReadyForFeatureCreation(); - // Synchronous call to ensure the new ImsFeature is ready before using the Feature. - void notifyImsFeatureReady(int slotId, int featureType); void removeImsFeature(int slotId, int featureType, in IImsFeatureStatusCallback c); IImsConfig getConfig(int slotId); IImsRegistration getRegistration(int slotId); diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index 2fffd36a1a4f..c073d1ab03d6 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -575,7 +575,7 @@ public class MmTelFeature extends ImsFeature { */ public ImsUtImplBase getUt() { // Base Implementation - Should be overridden - return null; + return new ImsUtImplBase(); } /** @@ -584,7 +584,7 @@ public class MmTelFeature extends ImsFeature { */ public ImsEcbmImplBase getEcbm() { // Base Implementation - Should be overridden - return null; + return new ImsEcbmImplBase(); } /** @@ -593,7 +593,7 @@ public class MmTelFeature extends ImsFeature { */ public ImsMultiEndpointImplBase getMultiEndpoint() { // Base Implementation - Should be overridden - return null; + return new ImsMultiEndpointImplBase(); } /** diff --git a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java index 98b67c3d3727..2f52c0ac2d99 100644 --- a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java +++ b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java @@ -21,6 +21,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.telephony.ims.feature.ImsFeature; import android.util.ArraySet; +import android.util.Pair; import java.util.Set; @@ -34,14 +35,57 @@ import java.util.Set; */ @SystemApi public final class ImsFeatureConfiguration implements Parcelable { + + public static final class FeatureSlotPair { + /** + * SIM slot that this feature is associated with. + */ + public final int slotId; + /** + * The feature that this slotId supports. Supported values are + * {@link ImsFeature#FEATURE_EMERGENCY_MMTEL}, {@link ImsFeature#FEATURE_MMTEL}, and + * {@link ImsFeature#FEATURE_RCS}. + */ + public final @ImsFeature.FeatureType int featureType; + + /** + * A mapping from slotId to IMS Feature type. + * @param slotId the SIM slot ID associated with this feature. + * @param featureType The feature that this slotId supports. Supported values are + * {@link ImsFeature#FEATURE_EMERGENCY_MMTEL}, {@link ImsFeature#FEATURE_MMTEL}, and + * {@link ImsFeature#FEATURE_RCS}. + */ + public FeatureSlotPair(int slotId, @ImsFeature.FeatureType int featureType) { + this.slotId = slotId; + this.featureType = featureType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + FeatureSlotPair that = (FeatureSlotPair) o; + + if (slotId != that.slotId) return false; + return featureType == that.featureType; + } + + @Override + public int hashCode() { + int result = slotId; + result = 31 * result + featureType; + return result; + } + } + /** * Features that this ImsService supports. */ - private final Set<Integer> mFeatures; + private final Set<FeatureSlotPair> mFeatures; /** - * Builder for {@link ImsFeatureConfiguration} that makes adding supported {@link ImsFeature}s - * easier. + * Builder for {@link ImsFeatureConfiguration}. */ public static class Builder { ImsFeatureConfiguration mConfig; @@ -50,12 +94,15 @@ public final class ImsFeatureConfiguration implements Parcelable { } /** - * @param feature A feature defined in {@link ImsFeature.FeatureType} that this service - * supports. + * Adds an IMS feature associated with a SIM slot ID. + * @param slotId The slot ID associated with the IMS feature. + * @param featureType The feature that the slot ID supports. Supported values are + * {@link ImsFeature#FEATURE_EMERGENCY_MMTEL}, {@link ImsFeature#FEATURE_MMTEL}, and + * {@link ImsFeature#FEATURE_RCS}. * @return a {@link Builder} to continue constructing the ImsFeatureConfiguration. */ - public Builder addFeature(@ImsFeature.FeatureType int feature) { - mConfig.addFeature(feature); + public Builder addFeature(int slotId, @ImsFeature.FeatureType int featureType) { + mConfig.addFeature(slotId, featureType); return this; } @@ -66,8 +113,7 @@ public final class ImsFeatureConfiguration implements Parcelable { /** * Creates with all registration features empty. - * - * Consider using the provided {@link Builder} to create this configuration instead. + * @hide */ public ImsFeatureConfiguration() { mFeatures = new ArraySet<>(); @@ -76,45 +122,41 @@ public final class ImsFeatureConfiguration implements Parcelable { /** * Configuration of the ImsService, which describes which features the ImsService supports * (for registration). - * @param features an array of feature integers defined in {@link ImsFeature} that describe - * which features this ImsService supports. Supported values are - * {@link ImsFeature#FEATURE_EMERGENCY_MMTEL}, {@link ImsFeature#FEATURE_MMTEL}, and - * {@link ImsFeature#FEATURE_RCS}. + * @param features a set of {@link FeatureSlotPair}s that describe which features this + * ImsService supports. * @hide */ - public ImsFeatureConfiguration(int[] features) { + public ImsFeatureConfiguration(Set<FeatureSlotPair> features) { mFeatures = new ArraySet<>(); if (features != null) { - for (int i : features) { - mFeatures.add(i); - } + mFeatures.addAll(features); } } /** - * @return an int[] containing the features that this ImsService supports. Supported values are - * {@link ImsFeature#FEATURE_EMERGENCY_MMTEL}, {@link ImsFeature#FEATURE_MMTEL}, and - * {@link ImsFeature#FEATURE_RCS}. + * @return a set of supported slot ID to feature type pairs contained within a + * {@link FeatureSlotPair}. */ - public int[] getServiceFeatures() { - return mFeatures.stream().mapToInt(i->i).toArray(); + public Set<FeatureSlotPair> getServiceFeatures() { + return new ArraySet<>(mFeatures); } - void addFeature(int feature) { - mFeatures.add(feature); + /** + * @hide + */ + void addFeature(int slotId, int feature) { + mFeatures.add(new FeatureSlotPair(slotId, feature)); } /** @hide */ protected ImsFeatureConfiguration(Parcel in) { - int[] features = in.createIntArray(); - if (features != null) { - mFeatures = new ArraySet<>(features.length); - for(Integer i : features) { - mFeatures.add(i); - } - } else { - mFeatures = new ArraySet<>(); + int featurePairLength = in.readInt(); + // length + mFeatures = new ArraySet<>(featurePairLength); + for (int i = 0; i < featurePairLength; i++) { + // pair of reads for each entry (slotId->featureType) + mFeatures.add(new FeatureSlotPair(in.readInt(), in.readInt())); } } @@ -138,7 +180,15 @@ public final class ImsFeatureConfiguration implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeIntArray(mFeatures.stream().mapToInt(i->i).toArray()); + FeatureSlotPair[] featureSlotPairs = new FeatureSlotPair[mFeatures.size()]; + mFeatures.toArray(featureSlotPairs); + // length of list + dest.writeInt(featureSlotPairs.length); + // then pairs of integers for each entry (slotId->featureType). + for (FeatureSlotPair featureSlotPair : featureSlotPairs) { + dest.writeInt(featureSlotPair.slotId); + dest.writeInt(featureSlotPair.featureType); + } } /** diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 4002d3c94db7..7c7700bb9a7d 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -829,6 +829,12 @@ interface ITelephony { boolean isEmergencyMmTelAvailable(int slotId); /** + * @return true if the IMS resolver is busy resolving a binding and should not be considered + * available, false if the IMS resolver is idle. + */ + boolean isResolvingImsBinding(); + + /** * Set the network selection mode to automatic. * * @param subId the id of the subscription to update. @@ -1438,13 +1444,12 @@ interface ITelephony { * Returns a list of Forbidden PLMNs from the specified SIM App * Returns null if the query fails. * - * - * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE + * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE * * @param subId subscription ID used for authentication * @param appType the icc application type, like {@link #APPTYPE_USIM} */ - String[] getForbiddenPlmns(int subId, int appType); + String[] getForbiddenPlmns(int subId, int appType, String callingPackage); /** * Check if phone is in emergency callback mode diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index a3a30807986e..ee7084ad86c0 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -25,6 +25,7 @@ package com.android.internal.telephony; */ import android.os.SystemProperties; +import android.telephony.TelephonyManager; /** * {@hide} @@ -162,8 +163,8 @@ public interface RILConstants { int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20; /* TD-SCDMA, GSM/WCDMA and LTE */ int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21; /*TD-SCDMA,EvDo,CDMA,GSM/WCDMA*/ int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; /* TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo */ - int PREFERRED_NETWORK_MODE = SystemProperties.getInt("ro.telephony.default_network", - NETWORK_MODE_WCDMA_PREF); + int PREFERRED_NETWORK_MODE = Integer.parseInt(TelephonyManager.getTelephonyProperty(0, + "ro.telephony.default_network", Integer.toString(NETWORK_MODE_WCDMA_PREF))); int BAND_MODE_UNSPECIFIED = 0; //"unspecified" (selected by baseband automatically) int BAND_MODE_EURO = 1; //"EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000) diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 93fa5987aa9c..6865f77fa717 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -86,9 +86,6 @@ public class WifiConfiguration implements Parcelable { /** WPA is not used; plaintext or static WEP could be used. */ public static final int NONE = 0; /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */ - /** @deprecated Due to security and performance limitations, use of WPA-1 networks - * is discouraged. WPA-2 (RSN) should be used instead. */ - @Deprecated public static final int WPA_PSK = 1; /** WPA using EAP authentication. Generally used with an external authentication server. */ public static final int WPA_EAP = 2; @@ -122,7 +119,7 @@ public class WifiConfiguration implements Parcelable { public static final String varName = "key_mgmt"; - public static final String[] strings = { "NONE", /* deprecated */ "WPA_PSK", "WPA_EAP", + public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP" }; } diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java index eca840644fc6..ebf60076bd02 100644 --- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java +++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java @@ -133,7 +133,8 @@ public class DiscoverySessionCallback { * match filter. For {@link PublishConfig#PUBLISH_TYPE_SOLICITED}, * {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE} discovery sessions this * is the subscriber's match filter. - * @param distanceMm The measured distance to the Publisher in mm. + * @param distanceMm The measured distance to the Publisher in mm. Note: the measured distance + * may be negative for very close devices. */ public void onServiceDiscoveredWithinRange(PeerHandle peerHandle, byte[] serviceSpecificInfo, List<byte[]> matchFilter, int distanceMm) { diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java index 2ec3b704f0f9..51353c618b97 100644 --- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java +++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java @@ -418,8 +418,8 @@ public final class SubscribeConfig implements Parcelable { * notification. I.e. discovery will be triggered if we've found a matching publisher * (based on the other criteria in this configuration) <b>and</b> the distance to the * publisher is larger than the value specified in this API. Can be used in conjunction with - * {@link #setMaxDistanceMm(int)} to specify a geofence, i.e. discovery with min < - * distance < max. + * {@link #setMaxDistanceMm(int)} to specify a geofence, i.e. discovery with min <= + * distance <= max. * <p> * For ranging to be used in discovery it must also be enabled on the publisher using * {@link PublishConfig.Builder#setRangingEnabled(boolean)}. However, ranging may @@ -453,8 +453,8 @@ public final class SubscribeConfig implements Parcelable { * notification. I.e. discovery will be triggered if we've found a matching publisher * (based on the other criteria in this configuration) <b>and</b> the distance to the * publisher is smaller than the value specified in this API. Can be used in conjunction - * with {@link #setMinDistanceMm(int)} to specify a geofence, i.e. discovery with min < - * distance < max. + * with {@link #setMinDistanceMm(int)} to specify a geofence, i.e. discovery with min <= + * distance <= max. * <p> * For ranging to be used in discovery it must also be enabled on the publisher using * {@link PublishConfig.Builder#setRangingEnabled(boolean)}. However, ranging may diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java index 936a1f2b6a47..7fe85be80964 100644 --- a/wifi/java/android/net/wifi/rtt/RangingResult.java +++ b/wifi/java/android/net/wifi/rtt/RangingResult.java @@ -147,6 +147,8 @@ public final class RangingResult implements Parcelable { * @return The distance (in mm) to the device specified by {@link #getMacAddress()} or * {@link #getPeerHandle()}. * <p> + * Note: the measured distance may be negative for very close devices. + * <p> * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an * exception. */ @@ -189,7 +191,8 @@ public final class RangingResult implements Parcelable { } /** - * @return The Location Configuration Information (LCI) as self-reported by the peer. + * @return The Location Configuration Information (LCI) as self-reported by the peer. The format + * is specified in the IEEE 802.11-2016 specifications, section 9.4.2.22.10. * <p> * Note: the information is NOT validated - use with caution. Consider validating it with * other sources of information before using it. @@ -207,7 +210,8 @@ public final class RangingResult implements Parcelable { } /** - * @return The Location Civic report (LCR) as self-reported by the peer. + * @return The Location Civic report (LCR) as self-reported by the peer. The format + * is specified in the IEEE 802.11-2016 specifications, section 9.4.2.22.13. * <p> * Note: the information is NOT validated - use with caution. Consider validating it with * other sources of information before using it. |