diff --git a/Android.bp b/Android.bp index 874c5a621549805988173b0a6a5591b48545f489..813816901313e25f921e656a9a94f51c95698941 100755 --- a/Android.bp +++ b/Android.bp @@ -463,6 +463,8 @@ java_library { "media/java/android/media/session/ISessionController.aidl", "media/java/android/media/session/ISessionControllerCallback.aidl", "media/java/android/media/session/ISessionManager.aidl", + "media/java/android/media/soundtrigger/ISoundTriggerDetectionService.aidl", + "media/java/android/media/soundtrigger/ISoundTriggerDetectionServiceClient.aidl", "media/java/android/media/tv/ITvInputClient.aidl", "media/java/android/media/tv/ITvInputHardware.aidl", "media/java/android/media/tv/ITvInputHardwareCallback.aidl", diff --git a/Android.mk b/Android.mk index bbe2faf2e9ed05dad1c8794a71c9bbc97049c372..e2f88e8990bd73c2c869d3804584867766376d1f 100755 --- a/Android.mk +++ b/Android.mk @@ -868,8 +868,12 @@ include $(BUILD_STATIC_JAVA_LIBRARY) $(eval $(call copy-one-file,frameworks/base/config/hiddenapi-blacklist.txt,\ $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST))) -$(eval $(call copy-one-file,frameworks/base/config/hiddenapi-light-greylist.txt,\ - $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST))) + +# Temporarily merge light greylist from two files. Vendor list will become dark +# grey once we remove the UI toast. +$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): frameworks/base/config/hiddenapi-light-greylist.txt \ + frameworks/base/config/hiddenapi-vendor-list.txt + sort $^ > $@ # Generate dark greylist as private API minus (blacklist plus light greylist). diff --git a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java index 7a32c0ccda075a5717524ef7abcec903d3d44263..e2b75c3f574680408532237feac1a600c3787d1d 100644 --- a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java +++ b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java @@ -117,6 +117,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); @@ -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/PrecomputedTextMemoryUsageTest.java b/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java index 73e17242ae785749a839fbf1124c072ca3d45284..ccbccca87b693d43d6fa688641099fd76c7cecc9 100644 --- a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java +++ b/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java @@ -119,8 +119,12 @@ public class PrecomputedTextMemoryUsageTest { // Report median of randomly generated PrecomputedText. for (int i = 0; i < TRIAL_COUNT; ++i) { CharSequence cs = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); - memories[i] = PrecomputedText.createWidthOnly(cs, param, 0, cs.length()) - .getMemoryUsage(); + PrecomputedText.ParagraphInfo[] paragraphInfo = + PrecomputedText.createMeasuredParagraphs(cs, param, 0, cs.length(), false); + memories[i] = 0; + for (PrecomputedText.ParagraphInfo info : paragraphInfo) { + memories[i] += info.measured.getMemoryUsage(); + } } reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation_WidthOnly"); } @@ -136,8 +140,12 @@ public class PrecomputedTextMemoryUsageTest { // Report median of randomly generated PrecomputedText. for (int i = 0; i < TRIAL_COUNT; ++i) { CharSequence cs = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); - memories[i] = PrecomputedText.createWidthOnly(cs, param, 0, cs.length()) - .getMemoryUsage(); + PrecomputedText.ParagraphInfo[] paragraphInfo = + PrecomputedText.createMeasuredParagraphs(cs, param, 0, cs.length(), false); + memories[i] = 0; + for (PrecomputedText.ParagraphInfo info : paragraphInfo) { + memories[i] += info.measured.getMemoryUsage(); + } } reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation_WidthOnly"); } diff --git a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java index dccb34be9d079420396477e52dd05a865e661bb3..fefda64b51a7f65f630834adcf961adc8c89b7cd 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 55b97e7675fd246f80b55101832cd35b0dfa29e7..dc34b7fe057cb41b4bad36f8025514177d2f58a6 100644 --- a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java @@ -116,6 +116,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(); @@ -178,6 +198,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(); @@ -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); @@ -239,11 +277,32 @@ 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 8efc7044af5fb317751afc876d65cb178a815bcc..332e2a49492014cba6a9665c9d47edfd61f3bcf4 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4265,6 +4265,7 @@ package android.app { public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 { ctor public Application(); + method public static java.lang.String getProcessName(); method public void onConfigurationChanged(android.content.res.Configuration); method public void onCreate(); method public void onLowMemory(); @@ -5195,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"; @@ -5399,6 +5401,7 @@ package android.app { method public android.app.Notification.Builder extend(android.app.Notification.Extender); method public android.os.Bundle getExtras(); method public deprecated android.app.Notification getNotification(); + method public android.app.Notification.Style getStyle(); method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification); method public android.app.Notification.Builder setActions(android.app.Notification.Action...); method public android.app.Notification.Builder setAutoCancel(boolean); @@ -5552,7 +5555,11 @@ package android.app { method public java.lang.String getKey(); method public java.lang.CharSequence getName(); method public java.lang.String getUri(); + method public boolean isBot(); + method public boolean isImportant(); + method public android.app.Notification.Person setBot(boolean); method public android.app.Notification.Person setIcon(android.graphics.drawable.Icon); + method public android.app.Notification.Person setImportant(boolean); method public android.app.Notification.Person setKey(java.lang.String); method public android.app.Notification.Person setName(java.lang.CharSequence); method public android.app.Notification.Person setUri(java.lang.String); @@ -6329,6 +6336,7 @@ package android.app.admin { method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException; method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); + method public boolean supportsTransferOwnership(); method public boolean usesPolicy(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; @@ -6393,7 +6401,6 @@ package android.app.admin { field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING"; field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE"; field public static final java.lang.String EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE = "android.app.extra.TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE"; - field public static final java.lang.String SUPPORT_TRANSFER_OWNERSHIP_META_DATA = "android.app.support_transfer_ownership"; } public class DeviceAdminService extends android.app.Service { @@ -7265,6 +7272,7 @@ package android.app.slice { public class SliceManager { method public android.app.slice.Slice bindSlice(android.net.Uri, java.util.List); method public android.app.slice.Slice bindSlice(android.content.Intent, java.util.List); + method public java.util.List getPinnedSlices(); method public java.util.List getPinnedSpecs(android.net.Uri); method public java.util.Collection getSliceDescendants(android.net.Uri); method public android.net.Uri mapIntentToUri(android.content.Intent); @@ -7274,10 +7282,16 @@ package android.app.slice { field public static final java.lang.String SLICE_METADATA_KEY = "android.metadata.SLICE_URI"; } + public class SliceMetrics { + ctor public SliceMetrics(android.content.Context, android.net.Uri); + method public void logHidden(); + method public void logTouch(android.net.Uri); + method public void logVisible(); + } + public abstract class SliceProvider extends android.content.ContentProvider { ctor public SliceProvider(); method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]); - method public final java.lang.String getBindingPackage(); method public final java.lang.String getType(android.net.Uri); method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues); method public android.app.slice.Slice onBindSlice(android.net.Uri, java.util.List); @@ -7418,12 +7432,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 } @@ -13602,7 +13618,9 @@ package android.graphics { public final class ImageDecoder implements java.lang.AutoCloseable { method public void close(); + method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, int); method public static android.graphics.ImageDecoder.Source createSource(android.content.ContentResolver, android.net.Uri); + method public static android.graphics.ImageDecoder.Source createSource(android.content.res.AssetManager, java.lang.String); method public static android.graphics.ImageDecoder.Source createSource(java.nio.ByteBuffer); method public static android.graphics.ImageDecoder.Source createSource(java.io.File); method public static android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException; @@ -14436,6 +14454,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 @@ -15767,7 +15786,7 @@ package android.hardware.camera2 { method public java.util.List> getAvailablePhysicalCameraRequestKeys(); method public java.util.List> getAvailableSessionKeys(); method public java.util.List> getKeys(); - method public java.util.List getPhysicalCameraIds(); + method public java.util.Set getPhysicalCameraIds(); field public static final android.hardware.camera2.CameraCharacteristics.Key COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES; field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES; field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_MODES; @@ -15793,6 +15812,7 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CameraCharacteristics.Key INFO_SUPPORTED_HARDWARE_LEVEL; field public static final android.hardware.camera2.CameraCharacteristics.Key INFO_VERSION; field public static final android.hardware.camera2.CameraCharacteristics.Key JPEG_AVAILABLE_THUMBNAIL_SIZES; + field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_DISTORTION; field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_FACING; field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_APERTURES; field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_FILTER_DENSITIES; @@ -15805,7 +15825,7 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_POSE_REFERENCE; field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_POSE_ROTATION; field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_POSE_TRANSLATION; - field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_RADIAL_DISTORTION; + field public static final deprecated android.hardware.camera2.CameraCharacteristics.Key LENS_RADIAL_DISTORTION; field public static final android.hardware.camera2.CameraCharacteristics.Key LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE; field public static final android.hardware.camera2.CameraCharacteristics.Key NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES; field public static final android.hardware.camera2.CameraCharacteristics.Key REPROCESS_MAX_CAPTURE_STALL; @@ -16263,6 +16283,7 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CaptureResult.Key JPEG_THUMBNAIL_QUALITY; field public static final android.hardware.camera2.CaptureResult.Key JPEG_THUMBNAIL_SIZE; field public static final android.hardware.camera2.CaptureResult.Key LENS_APERTURE; + field public static final android.hardware.camera2.CaptureResult.Key LENS_DISTORTION; field public static final android.hardware.camera2.CaptureResult.Key LENS_FILTER_DENSITY; field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCAL_LENGTH; field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCUS_DISTANCE; @@ -16271,7 +16292,7 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CaptureResult.Key LENS_OPTICAL_STABILIZATION_MODE; field public static final android.hardware.camera2.CaptureResult.Key LENS_POSE_ROTATION; field public static final android.hardware.camera2.CaptureResult.Key LENS_POSE_TRANSLATION; - field public static final android.hardware.camera2.CaptureResult.Key LENS_RADIAL_DISTORTION; + field public static final deprecated android.hardware.camera2.CaptureResult.Key LENS_RADIAL_DISTORTION; field public static final android.hardware.camera2.CaptureResult.Key LENS_STATE; field public static final android.hardware.camera2.CaptureResult.Key NOISE_REDUCTION_MODE; field public static final android.hardware.camera2.CaptureResult.Key REPROCESS_EFFECTIVE_EXPOSURE_FACTOR; @@ -21244,9 +21265,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 { @@ -23257,6 +23279,7 @@ package android.media { field public static final int HEVCProfileMain = 1; // 0x1 field public static final int HEVCProfileMain10 = 2; // 0x2 field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000 + field public static final int HEVCProfileMainStill = 4; // 0x4 field public static final int MPEG2LevelH14 = 2; // 0x2 field public static final int MPEG2LevelHL = 3; // 0x3 field public static final int MPEG2LevelHP = 4; // 0x4 @@ -23770,10 +23793,8 @@ package android.media { field public static final java.lang.String KEY_DURATION = "durationUs"; field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level"; field public static final java.lang.String KEY_FRAME_RATE = "frame-rate"; - field public static final java.lang.String KEY_GRID_COLS = "grid-cols"; - field public static final java.lang.String KEY_GRID_HEIGHT = "grid-height"; + field public static final java.lang.String KEY_GRID_COLUMNS = "grid-cols"; field public static final java.lang.String KEY_GRID_ROWS = "grid-rows"; - field public static final java.lang.String KEY_GRID_WIDTH = "grid-width"; field public static final java.lang.String KEY_HDR_STATIC_INFO = "hdr-static-info"; field public static final java.lang.String KEY_HEIGHT = "height"; field public static final java.lang.String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period"; @@ -23802,6 +23823,8 @@ package android.media { field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height"; field public static final java.lang.String KEY_STRIDE = "stride"; field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema"; + field public static final java.lang.String KEY_TILE_HEIGHT = "tile-height"; + field public static final java.lang.String KEY_TILE_WIDTH = "tile-width"; field public static final java.lang.String KEY_TRACK_ID = "track-id"; field public static final java.lang.String KEY_WIDTH = "width"; field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm"; @@ -24050,12 +24073,16 @@ package android.media { ctor public MediaMetadataRetriever(); method public java.lang.String extractMetadata(int); method public byte[] getEmbeddedPicture(); + method public android.graphics.Bitmap getFrameAtIndex(int, android.media.MediaMetadataRetriever.BitmapParams); method public android.graphics.Bitmap getFrameAtIndex(int); method public android.graphics.Bitmap getFrameAtTime(long, int); method public android.graphics.Bitmap getFrameAtTime(long); method public android.graphics.Bitmap getFrameAtTime(); - method public android.graphics.Bitmap[] getFramesAtIndex(int, int); + method public java.util.List getFramesAtIndex(int, int, android.media.MediaMetadataRetriever.BitmapParams); + method public java.util.List getFramesAtIndex(int, int); + method public android.graphics.Bitmap getImageAtIndex(int, android.media.MediaMetadataRetriever.BitmapParams); method public android.graphics.Bitmap getImageAtIndex(int); + method public android.graphics.Bitmap getPrimaryImage(android.media.MediaMetadataRetriever.BitmapParams); method public android.graphics.Bitmap getPrimaryImage(); method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int); method public void release(); @@ -24102,6 +24129,13 @@ package android.media { field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0 } + public static final class MediaMetadataRetriever.BitmapParams { + ctor public MediaMetadataRetriever.BitmapParams(); + method public android.graphics.Bitmap.Config getActualConfig(); + method public android.graphics.Bitmap.Config getPreferredConfig(); + method public void setPreferredConfig(android.graphics.Bitmap.Config); + } + public final class MediaMuxer { ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException; ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException; @@ -24349,7 +24383,6 @@ package android.media { method public abstract android.media.MediaDrm.KeyRequest getDrmKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map) throws android.media.MediaPlayer2.NoDrmSchemeException; method public abstract java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer2.NoDrmSchemeException; method public abstract long getDuration(); - method public abstract int getMediaPlayer2State(); method public abstract android.os.PersistableBundle getMetrics(); method public abstract android.media.PlaybackParams getPlaybackParams(); method public abstract int getSelectedTrack(int); @@ -24375,33 +24408,35 @@ package android.media { method public abstract void setPlaybackParams(android.media.PlaybackParams); method public abstract void setSurface(android.view.Surface); method public abstract void setSyncParams(android.media.SyncParams); - field public static final int MEDIAPLAYER2_STATE_ERROR = 5; // 0x5 - field public static final int MEDIAPLAYER2_STATE_IDLE = 1; // 0x1 - field public static final int MEDIAPLAYER2_STATE_PAUSED = 3; // 0x3 - field public static final int MEDIAPLAYER2_STATE_PLAYING = 4; // 0x4 - field public static final int MEDIAPLAYER2_STATE_PREPARED = 2; // 0x2 - field public static final int MEDIA_CALL_ATTACH_AUX_EFFECT = 1; // 0x1 - field public static final int MEDIA_CALL_DESELECT_TRACK = 2; // 0x2 - field public static final int MEDIA_CALL_LOOP_CURRENT = 3; // 0x3 - field public static final int MEDIA_CALL_PAUSE = 4; // 0x4 - field public static final int MEDIA_CALL_PLAY = 5; // 0x5 - field public static final int MEDIA_CALL_PREPARE = 6; // 0x6 - field public static final int MEDIA_CALL_RELEASE_DRM = 12; // 0xc - field public static final int MEDIA_CALL_RESTORE_DRM_KEYS = 13; // 0xd - field public static final int MEDIA_CALL_SEEK_TO = 14; // 0xe - field public static final int MEDIA_CALL_SELECT_TRACK = 15; // 0xf - field public static final int MEDIA_CALL_SET_AUDIO_ATTRIBUTES = 16; // 0x10 - field public static final int MEDIA_CALL_SET_AUDIO_SESSION_ID = 17; // 0x11 - field public static final int MEDIA_CALL_SET_AUX_EFFECT_SEND_LEVEL = 18; // 0x12 - field public static final int MEDIA_CALL_SET_DATA_SOURCE = 19; // 0x13 - field public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCE = 22; // 0x16 - field public static final int MEDIA_CALL_SET_NEXT_DATA_SOURCES = 23; // 0x17 - field public static final int MEDIA_CALL_SET_PLAYBACK_PARAMS = 24; // 0x18 - field public static final int MEDIA_CALL_SET_PLAYBACK_SPEED = 25; // 0x19 - field public static final int MEDIA_CALL_SET_PLAYER_VOLUME = 26; // 0x1a - field public static final int MEDIA_CALL_SET_SURFACE = 27; // 0x1b - field public static final int MEDIA_CALL_SET_SYNC_PARAMS = 28; // 0x1c - field public static final int MEDIA_CALL_SKIP_TO_NEXT = 29; // 0x1d + field public static final int CALL_COMPLETED_ATTACH_AUX_EFFECT = 1; // 0x1 + field public static final int CALL_COMPLETED_DESELECT_TRACK = 2; // 0x2 + field public static final int CALL_COMPLETED_LOOP_CURRENT = 3; // 0x3 + field public static final int CALL_COMPLETED_PAUSE = 4; // 0x4 + field public static final int CALL_COMPLETED_PLAY = 5; // 0x5 + field public static final int CALL_COMPLETED_PREPARE = 6; // 0x6 + field public static final int CALL_COMPLETED_RELEASE_DRM = 12; // 0xc + field public static final int CALL_COMPLETED_RESTORE_DRM_KEYS = 13; // 0xd + field public static final int CALL_COMPLETED_SEEK_TO = 14; // 0xe + field public static final int CALL_COMPLETED_SELECT_TRACK = 15; // 0xf + field public static final int CALL_COMPLETED_SET_AUDIO_ATTRIBUTES = 16; // 0x10 + field public static final int CALL_COMPLETED_SET_AUDIO_SESSION_ID = 17; // 0x11 + field public static final int CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL = 18; // 0x12 + field public static final int CALL_COMPLETED_SET_DATA_SOURCE = 19; // 0x13 + field public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCE = 22; // 0x16 + field public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCES = 23; // 0x17 + field public static final int CALL_COMPLETED_SET_PLAYBACK_PARAMS = 24; // 0x18 + field public static final int CALL_COMPLETED_SET_PLAYBACK_SPEED = 25; // 0x19 + field public static final int CALL_COMPLETED_SET_PLAYER_VOLUME = 26; // 0x1a + field public static final int CALL_COMPLETED_SET_SURFACE = 27; // 0x1b + field public static final int CALL_COMPLETED_SET_SYNC_PARAMS = 28; // 0x1c + field public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29; // 0x1d + field public static final int CALL_STATUS_BAD_VALUE = 2; // 0x2 + field public static final int CALL_STATUS_ERROR_IO = 4; // 0x4 + field public static final int CALL_STATUS_ERROR_UNKNOWN = -2147483648; // 0x80000000 + field public static final int CALL_STATUS_INVALID_OPERATION = 1; // 0x1 + field public static final int CALL_STATUS_NO_DRM_SCHEME = 5; // 0x5 + field public static final int CALL_STATUS_NO_ERROR = 0; // 0x0 + field public static final int CALL_STATUS_PERMISSION_DENIED = 3; // 0x3 field public static final int MEDIA_ERROR_IO = -1004; // 0xfffffc14 field public static final int MEDIA_ERROR_MALFORMED = -1007; // 0xfffffc11 field public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200; // 0xc8 @@ -24451,7 +24486,7 @@ package android.media { public static abstract class MediaPlayer2.MediaPlayer2EventCallback { ctor public MediaPlayer2.MediaPlayer2EventCallback(); - method public void onCallComplete(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int); + method public void onCallCompleted(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int); method public void onCommandLabelReached(android.media.MediaPlayer2, java.lang.Object); method public void onError(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int); method public void onInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int); @@ -28667,7 +28702,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"; } @@ -29454,7 +29489,7 @@ package android.nfc { field public static final java.lang.String EXTRA_ID = "android.nfc.extra.ID"; field public static final java.lang.String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES"; field public static final java.lang.String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence"; - field public static final java.lang.String EXTRA_SE_NAME = "android.nfc.extra.SE_NAME"; + field public static final java.lang.String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME"; field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG"; field public static final int FLAG_READER_NFC_A = 1; // 0x1 field public static final int FLAG_READER_NFC_B = 2; // 0x2 @@ -33159,6 +33194,8 @@ package android.os { ctor public Handler(android.os.Handler.Callback); ctor public Handler(android.os.Looper); ctor public Handler(android.os.Looper, android.os.Handler.Callback); + method public static android.os.Handler createAsync(android.os.Looper); + method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback); method public void dispatchMessage(android.os.Message); method public final void dump(android.util.Printer, java.lang.String); method public final android.os.Looper getLooper(); @@ -40025,6 +40062,7 @@ package android.service.notification { method public int getSuppressedVisualEffects(); method public int getUserSentiment(); method public boolean isAmbient(); + method public boolean isSuspended(); method public boolean matchesInterruptionFilter(); field public static final int USER_SENTIMENT_NEGATIVE = -1; // 0xffffffff field public static final int USER_SENTIMENT_NEUTRAL = 0; // 0x0 @@ -42806,17 +42844,17 @@ package android.telephony { ctor public ServiceState(android.os.Parcel); method protected void copyFrom(android.telephony.ServiceState); method public int describeContents(); + method public int getCdmaNetworkId(); + method public int getCdmaSystemId(); method public int[] getCellBandwidths(); method public int getChannelNumber(); method public int getDuplexMode(); method public boolean getIsManualSelection(); - method public int getNetworkId(); method public java.lang.String getOperatorAlphaLong(); method public java.lang.String getOperatorAlphaShort(); method public java.lang.String getOperatorNumeric(); method public boolean getRoaming(); method public int getState(); - method public int getSystemId(); method public void setIsManualSelection(boolean); method public void setOperatorName(java.lang.String, java.lang.String, java.lang.String); method public void setRoaming(boolean); @@ -43071,8 +43109,6 @@ package android.telephony { method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle); method public android.telephony.TelephonyManager createForSubscriptionId(int); method public java.util.List getAllCellInfo(); - method public int getAndroidCarrierIdForSubscription(); - method public java.lang.CharSequence getAndroidCarrierNameForSubscription(); method public int getCallState(); method public android.os.PersistableBundle getCarrierConfig(); method public deprecated android.telephony.CellLocation getCellLocation(); @@ -43103,6 +43139,8 @@ package android.telephony { method public int getPhoneType(); method public android.telephony.ServiceState getServiceState(); method public android.telephony.SignalStrength getSignalStrength(); + method public int getSimCarrierId(); + method public java.lang.CharSequence getSimCarrierIdName(); method public java.lang.String getSimCountryIso(); method public java.lang.String getSimOperator(); method public java.lang.String getSimOperatorName(); @@ -43321,21 +43359,21 @@ package android.telephony.data { public class ApnSetting implements android.os.Parcelable { method public int describeContents(); method public java.lang.String getApnName(); + method public int getApnTypeBitmask(); method public int getAuthType(); method public java.lang.String getEntryName(); method public int getId(); - method public int getMmsPort(); - method public java.net.InetAddress getMmsProxy(); - method public java.net.URL getMmsc(); - method public java.lang.String getMvnoType(); + method public java.net.InetAddress getMmsProxyAddress(); + method public int getMmsProxyPort(); + method public android.net.Uri getMmsc(); + method public int getMvnoType(); method public int getNetworkTypeBitmask(); method public java.lang.String getOperatorNumeric(); method public java.lang.String getPassword(); - method public int getPort(); - method public java.lang.String getProtocol(); - method public java.net.InetAddress getProxy(); - method public java.lang.String getRoamingProtocol(); - method public java.util.List getTypes(); + method public int getProtocol(); + method public java.net.InetAddress getProxyAddress(); + method public int getProxyPort(); + method public int getRoamingProtocol(); method public java.lang.String getUser(); method public boolean isEnabled(); method public void writeToParcel(android.os.Parcel, int); @@ -43344,46 +43382,45 @@ package android.telephony.data { field public static final int AUTH_TYPE_PAP = 1; // 0x1 field public static final int AUTH_TYPE_PAP_OR_CHAP = 3; // 0x3 field public static final android.os.Parcelable.Creator CREATOR; - field public static final java.lang.String MVNO_TYPE_GID = "gid"; - field public static final java.lang.String MVNO_TYPE_ICCID = "iccid"; - field public static final java.lang.String MVNO_TYPE_IMSI = "imsi"; - field public static final java.lang.String MVNO_TYPE_SPN = "spn"; - field public static final java.lang.String PROTOCOL_IP = "IP"; - field public static final java.lang.String PROTOCOL_IPV4V6 = "IPV4V6"; - field public static final java.lang.String PROTOCOL_IPV6 = "IPV6"; - field public static final java.lang.String PROTOCOL_PPP = "PPP"; - field public static final java.lang.String TYPE_ALL = "*"; - field public static final java.lang.String TYPE_CBS = "cbs"; - field public static final java.lang.String TYPE_DEFAULT = "default"; - field public static final java.lang.String TYPE_DUN = "dun"; - field public static final java.lang.String TYPE_EMERGENCY = "emergency"; - field public static final java.lang.String TYPE_FOTA = "fota"; - field public static final java.lang.String TYPE_HIPRI = "hipri"; - field public static final java.lang.String TYPE_IA = "ia"; - field public static final java.lang.String TYPE_IMS = "ims"; - field public static final java.lang.String TYPE_MMS = "mms"; - field public static final java.lang.String TYPE_SUPL = "supl"; + field public static final int MVNO_TYPE_GID = 2; // 0x2 + field public static final int MVNO_TYPE_ICCID = 3; // 0x3 + field public static final int MVNO_TYPE_IMSI = 1; // 0x1 + field public static final int MVNO_TYPE_SPN = 0; // 0x0 + field public static final int PROTOCOL_IP = 0; // 0x0 + field public static final int PROTOCOL_IPV4V6 = 2; // 0x2 + field public static final int PROTOCOL_IPV6 = 1; // 0x1 + field public static final int PROTOCOL_PPP = 3; // 0x3 + field public static final int TYPE_CBS = 128; // 0x80 + field public static final int TYPE_DEFAULT = 17; // 0x11 + field public static final int TYPE_DUN = 8; // 0x8 + field public static final int TYPE_EMERGENCY = 512; // 0x200 + field public static final int TYPE_FOTA = 32; // 0x20 + field public static final int TYPE_HIPRI = 16; // 0x10 + field public static final int TYPE_IA = 256; // 0x100 + field public static final int TYPE_IMS = 64; // 0x40 + field public static final int TYPE_MMS = 2; // 0x2 + field public static final int TYPE_SUPL = 4; // 0x4 } public static class ApnSetting.Builder { ctor public ApnSetting.Builder(); method public android.telephony.data.ApnSetting build(); method public android.telephony.data.ApnSetting.Builder setApnName(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setApnTypeBitmask(int); method public android.telephony.data.ApnSetting.Builder setAuthType(int); method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean); method public android.telephony.data.ApnSetting.Builder setEntryName(java.lang.String); - method public android.telephony.data.ApnSetting.Builder setMmsPort(int); - method public android.telephony.data.ApnSetting.Builder setMmsProxy(java.net.InetAddress); - method public android.telephony.data.ApnSetting.Builder setMmsc(java.net.URL); - method public android.telephony.data.ApnSetting.Builder setMvnoType(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.net.InetAddress); + method public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int); + method public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri); + method public android.telephony.data.ApnSetting.Builder setMvnoType(int); method public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int); method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(java.lang.String); method public android.telephony.data.ApnSetting.Builder setPassword(java.lang.String); - method public android.telephony.data.ApnSetting.Builder setPort(int); - method public android.telephony.data.ApnSetting.Builder setProtocol(java.lang.String); - method public android.telephony.data.ApnSetting.Builder setProxy(java.net.InetAddress); - method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(java.lang.String); - method public android.telephony.data.ApnSetting.Builder setTypes(java.util.List); + method public android.telephony.data.ApnSetting.Builder setProtocol(int); + method public android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress); + method public android.telephony.data.ApnSetting.Builder setProxyPort(int); + method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int); method public android.telephony.data.ApnSetting.Builder setUser(java.lang.String); } @@ -46623,8 +46660,8 @@ package android.view { } public final class DisplayCutout { - ctor public DisplayCutout(android.graphics.Rect, android.graphics.Region); - method public android.graphics.Region getBounds(); + ctor public DisplayCutout(android.graphics.Rect, java.util.List); + method public java.util.List getBoundingRects(); method public int getSafeInsetBottom(); method public int getSafeInsetLeft(); method public int getSafeInsetRight(); @@ -49698,9 +49735,9 @@ package android.view { field public static final int LAST_SUB_WINDOW = 1999; // 0x7cf field public static final int LAST_SYSTEM_WINDOW = 2999; // 0xbb7 field public static final int LAYOUT_CHANGED = 1; // 0x1 - field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; // 0x1 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; // 0x0 field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; // 0x2 + field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1; // 0x1 field public static final int MEMORY_TYPE_CHANGED = 256; // 0x100 field public static final deprecated int MEMORY_TYPE_GPU = 2; // 0x2 field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1 @@ -51036,6 +51073,77 @@ package android.view.inputmethod { package android.view.textclassifier { + public abstract class Logger { + ctor public Logger(android.view.textclassifier.Logger.Config); + method public java.text.BreakIterator getTokenIterator(java.util.Locale); + method public boolean isSmartSelection(java.lang.String); + method public final void logSelectionActionEvent(int, int, int); + method public final void logSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification); + method public final void logSelectionModifiedEvent(int, int); + method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification); + method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection); + method public final void logSelectionStartedEvent(int, int); + method public abstract void writeEvent(android.view.textclassifier.SelectionEvent); + field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff + field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000 + field public static final java.lang.String WIDGET_CUSTOM_EDITTEXT = "customedit"; + field public static final java.lang.String WIDGET_CUSTOM_TEXTVIEW = "customview"; + field public static final java.lang.String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview"; + field public static final java.lang.String WIDGET_EDITTEXT = "edittext"; + field public static final java.lang.String WIDGET_EDIT_WEBVIEW = "edit-webview"; + field public static final java.lang.String WIDGET_TEXTVIEW = "textview"; + field public static final java.lang.String WIDGET_UNKNOWN = "unknown"; + field public static final java.lang.String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview"; + field public static final java.lang.String WIDGET_WEBVIEW = "webview"; + } + + public static final class Logger.Config { + ctor public Logger.Config(android.content.Context, java.lang.String, java.lang.String); + method public java.lang.String getPackageName(); + method public java.lang.String getWidgetType(); + method public java.lang.String getWidgetVersion(); + } + + public final class SelectionEvent implements android.os.Parcelable { + method public int describeContents(); + method public long getDurationSincePreviousEvent(); + method public long getDurationSinceSessionStart(); + method public int getEnd(); + method public java.lang.String getEntityType(); + method public int getEventIndex(); + method public long getEventTime(); + method public int getEventType(); + method public int getInvocationMethod(); + method public java.lang.String getPackageName(); + method public java.lang.String getSessionId(); + method public java.lang.String getSignature(); + method public int getSmartEnd(); + method public int getSmartStart(); + method public int getStart(); + method public java.lang.String getWidgetType(); + method public java.lang.String getWidgetVersion(); + method public void writeToParcel(android.os.Parcel, int); + field public static final int ACTION_ABANDON = 107; // 0x6b + field public static final int ACTION_COPY = 101; // 0x65 + field public static final int ACTION_CUT = 103; // 0x67 + field public static final int ACTION_DRAG = 106; // 0x6a + field public static final int ACTION_OTHER = 108; // 0x6c + field public static final int ACTION_OVERTYPE = 100; // 0x64 + field public static final int ACTION_PASTE = 102; // 0x66 + field public static final int ACTION_RESET = 201; // 0xc9 + field public static final int ACTION_SELECT_ALL = 200; // 0xc8 + field public static final int ACTION_SHARE = 104; // 0x68 + field public static final int ACTION_SMART_SHARE = 105; // 0x69 + field public static final android.os.Parcelable.Creator CREATOR; + field public static final int EVENT_AUTO_SELECTION = 5; // 0x5 + field public static final int EVENT_SELECTION_MODIFIED = 2; // 0x2 + field public static final int EVENT_SELECTION_STARTED = 1; // 0x1 + field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4 + field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3 + field public static final int INVOCATION_LINK = 2; // 0x2 + field public static final int INVOCATION_MANUAL = 1; // 0x1 + } + public final class TextClassification implements android.os.Parcelable { method public int describeContents(); method public float getConfidenceScore(java.lang.String); @@ -51092,7 +51200,7 @@ package android.view.textclassifier { method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList); method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options); method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence); - method public default android.view.textclassifier.logging.Logger getLogger(android.view.textclassifier.logging.Logger.Config); + method public default android.view.textclassifier.Logger getLogger(android.view.textclassifier.Logger.Config); method public default int getMaxGenerateLinksTextLength(); method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options); method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int); @@ -51205,78 +51313,6 @@ package android.view.textclassifier { } -package android.view.textclassifier.logging { - - public abstract class Logger { - ctor public Logger(android.view.textclassifier.logging.Logger.Config); - method public java.text.BreakIterator getTokenIterator(java.util.Locale); - method public boolean isSmartSelection(java.lang.String); - method public final void logSelectionActionEvent(int, int, int); - method public final void logSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification); - method public final void logSelectionModifiedEvent(int, int); - method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification); - method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection); - method public final void logSelectionStartedEvent(int, int); - method public abstract void writeEvent(android.view.textclassifier.logging.SelectionEvent); - field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff - field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000 - field public static final java.lang.String WIDGET_CUSTOM_EDITTEXT = "customedit"; - field public static final java.lang.String WIDGET_CUSTOM_TEXTVIEW = "customview"; - field public static final java.lang.String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview"; - field public static final java.lang.String WIDGET_EDITTEXT = "edittext"; - field public static final java.lang.String WIDGET_EDIT_WEBVIEW = "edit-webview"; - field public static final java.lang.String WIDGET_TEXTVIEW = "textview"; - field public static final java.lang.String WIDGET_UNKNOWN = "unknown"; - field public static final java.lang.String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview"; - field public static final java.lang.String WIDGET_WEBVIEW = "webview"; - } - - public static final class Logger.Config { - ctor public Logger.Config(android.content.Context, java.lang.String, java.lang.String); - method public java.lang.String getPackageName(); - method public java.lang.String getWidgetType(); - method public java.lang.String getWidgetVersion(); - } - - public final class SelectionEvent { - method public long getDurationSincePreviousEvent(); - method public long getDurationSinceSessionStart(); - method public int getEnd(); - method public java.lang.String getEntityType(); - method public int getEventIndex(); - method public long getEventTime(); - method public int getEventType(); - method public int getInvocationMethod(); - method public java.lang.String getPackageName(); - method public java.lang.String getSessionId(); - method public java.lang.String getSignature(); - method public int getSmartEnd(); - method public int getSmartStart(); - method public int getStart(); - method public java.lang.String getWidgetType(); - method public java.lang.String getWidgetVersion(); - field public static final int ACTION_ABANDON = 107; // 0x6b - field public static final int ACTION_COPY = 101; // 0x65 - field public static final int ACTION_CUT = 103; // 0x67 - field public static final int ACTION_DRAG = 106; // 0x6a - field public static final int ACTION_OTHER = 108; // 0x6c - field public static final int ACTION_OVERTYPE = 100; // 0x64 - field public static final int ACTION_PASTE = 102; // 0x66 - field public static final int ACTION_RESET = 201; // 0xc9 - field public static final int ACTION_SELECT_ALL = 200; // 0xc8 - field public static final int ACTION_SHARE = 104; // 0x68 - field public static final int ACTION_SMART_SHARE = 105; // 0x69 - field public static final int EVENT_AUTO_SELECTION = 5; // 0x5 - field public static final int EVENT_SELECTION_MODIFIED = 2; // 0x2 - field public static final int EVENT_SELECTION_STARTED = 1; // 0x1 - field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4 - field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3 - field public static final int INVOCATION_LINK = 2; // 0x2 - field public static final int INVOCATION_MANUAL = 1; // 0x1 - } - -} - package android.view.textservice { public final class SentenceSuggestionsInfo implements android.os.Parcelable { diff --git a/api/system-current.txt b/api/system-current.txt index d35a06be45dfa5bdc7038927585a27e32900bf14..a5be12fdfc9cc4fbdea2354a0f3ad45c8197f36d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -32,6 +32,7 @@ package android { field public static final java.lang.String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE"; field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE"; field public static final java.lang.String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE"; + field public static final java.lang.String BIND_SOUND_TRIGGER_DETECTION_SERVICE = "android.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE"; field public static final java.lang.String BIND_TELEPHONY_DATA_SERVICE = "android.permission.BIND_TELEPHONY_DATA_SERVICE"; field public static final java.lang.String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE"; field public static final java.lang.String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE"; @@ -99,6 +100,7 @@ package android { field public static final java.lang.String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE"; field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES"; field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS"; + field public static final java.lang.String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER"; field public static final java.lang.String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS"; field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB"; field public static final java.lang.String MANAGE_USERS = "android.permission.MANAGE_USERS"; @@ -261,6 +263,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"; @@ -275,8 +278,8 @@ package android.app { field public static final java.lang.String OPSTR_AUDIO_NOTIFICATION_VOLUME = "android:audio_notification_volume"; field public static final java.lang.String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume"; field public static final java.lang.String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume"; - field public static final java.lang.String OPSTR_BIND_ACCESSIBILITY_SERVICE = "bind_accessibility_service"; - field public static final java.lang.String OPSTR_CHANGE_WIFI_STATE = "change_wifi_state"; + field public static final java.lang.String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service"; + field public static final java.lang.String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state"; field public static final java.lang.String OPSTR_GET_ACCOUNTS = "android:get_accounts"; field public static final java.lang.String OPSTR_GPS = "android:gps"; field public static final java.lang.String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground"; @@ -288,7 +291,7 @@ package android.app { field public static final java.lang.String OPSTR_READ_CLIPBOARD = "android:read_clipboard"; field public static final java.lang.String OPSTR_READ_ICC_SMS = "android:read_icc_sms"; field public static final java.lang.String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast"; - field public static final java.lang.String OPSTR_REQUEST_DELETE_PACKAGES = "request_delete_packages"; + field public static final java.lang.String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages"; field public static final java.lang.String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages"; field public static final java.lang.String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background"; field public static final java.lang.String OPSTR_RUN_IN_BACKGROUND = "android:run_in_background"; @@ -335,6 +338,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 @@ -369,7 +375,6 @@ package android.app { } public final class StatsManager { - method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String); method public boolean addConfiguration(long, byte[]); method public byte[] getData(long); method public byte[] getMetadata(); @@ -377,6 +382,7 @@ package android.app { method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent); method public boolean setDataFetchOperation(long, android.app.PendingIntent); field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED"; + field public static final java.lang.String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES"; field public static final java.lang.String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY"; field public static final java.lang.String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID"; field public static final java.lang.String EXTRA_STATS_DIMENSIONS_VALUE = "android.app.extra.STATS_DIMENSIONS_VALUE"; @@ -716,17 +722,23 @@ package android.app.usage { } public static final class UsageEvents.Event { - method public int getStandbyBucket(); + method public java.lang.String getNotificationChannelId(); + 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 + field public static final int SYSTEM_INTERACTION = 6; // 0x6 } public final class UsageStatsManager { method public int getAppStandbyBucket(java.lang.String); method public java.util.Map getAppStandbyBuckets(); + method public void registerAppUsageObserver(int, java.lang.String[], long, java.util.concurrent.TimeUnit, android.app.PendingIntent); method public void setAppStandbyBucket(java.lang.String, int); method public void setAppStandbyBuckets(java.util.Map); + method public void unregisterAppUsageObserver(int); method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle); + field public static final java.lang.String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID"; + field public static final java.lang.String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT"; + field public static final java.lang.String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED"; field public static final int STANDBY_BUCKET_EXEMPTED = 5; // 0x5 field public static final int STANDBY_BUCKET_NEVER = 50; // 0x32 } @@ -1223,7 +1235,9 @@ package android.hardware.display { public final class DisplayManager { method public java.util.List getAmbientBrightnessStats(); + method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration(); method public java.util.List getBrightnessEvents(); + method public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration(); method public android.graphics.Point getStableDisplaySize(); method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration); } @@ -2210,6 +2224,21 @@ package android.hardware.radio { } +package android.hardware.soundtrigger { + + public class SoundTrigger { + field public static final int STATUS_OK = 0; // 0x0 + } + + public static class SoundTrigger.RecognitionEvent { + method public android.media.AudioFormat getCaptureFormat(); + method public int getCaptureSession(); + method public byte[] getData(); + method public boolean isCaptureAvailable(); + } + +} + package android.hardware.usb { public class UsbDeviceConnection { @@ -2725,6 +2754,16 @@ package android.media.session { package android.media.soundtrigger { + public abstract class SoundTriggerDetectionService extends android.app.Service { + ctor public SoundTriggerDetectionService(); + method public void onConnected(java.util.UUID, android.os.Bundle); + method public void onDisconnected(java.util.UUID, android.os.Bundle); + method public void onError(java.util.UUID, android.os.Bundle, int, int); + method public void onGenericRecognitionEvent(java.util.UUID, android.os.Bundle, int, android.hardware.soundtrigger.SoundTrigger.RecognitionEvent); + method public abstract void onStopOperation(java.util.UUID, android.os.Bundle, int); + method public final void operationFinished(java.util.UUID, int); + } + public final class SoundTriggerDetector { method public boolean startRecognition(int); method public boolean stopRecognition(); @@ -2749,6 +2788,7 @@ package android.media.soundtrigger { public final class SoundTriggerManager { method public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, android.media.soundtrigger.SoundTriggerDetector.Callback, android.os.Handler); method public void deleteModel(java.util.UUID); + method public int getDetectionServiceOperationsTimeout(); method public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID); method public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model); } @@ -3760,7 +3800,6 @@ package android.os { public class IncidentManager { method public void reportIncident(android.os.IncidentReportArgs); - method public void reportIncident(java.lang.String, byte[]); } public final class IncidentReportArgs implements android.os.Parcelable { @@ -3771,7 +3810,6 @@ package android.os { method public boolean containsSection(int); method public int describeContents(); method public boolean isAll(); - method public static android.os.IncidentReportArgs parseSetting(java.lang.String) throws java.lang.IllegalArgumentException; method public void readFromParcel(android.os.Parcel); method public int sectionCount(); method public void setAll(boolean); @@ -4322,11 +4360,14 @@ package android.security.keystore.recovery { method public deprecated java.util.List getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public java.util.List getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException; method public static android.security.keystore.recovery.RecoveryController getInstance(android.content.Context); + method public java.security.Key getKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException; + method public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException; method public int[] getPendingRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException; method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException; method public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException; method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public int getRecoveryStatus(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; + method public java.security.Key importKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException; method public deprecated void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException; method public void initRecoveryService(java.lang.String, byte[], byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException; method public void recoverySecretAvailable(android.security.keystore.recovery.KeyChainProtectionParams) throws android.security.keystore.recovery.InternalRecoveryServiceException; @@ -4703,9 +4744,11 @@ package android.service.textclassifier { public abstract class TextClassifierService extends android.app.Service { ctor public TextClassifierService(); + method public final android.view.textclassifier.TextClassifier getLocalTextClassifier(); method public final android.os.IBinder onBind(android.content.Intent); method public abstract void onClassifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback); method public abstract void onGenerateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback); + method public void onSelectionEvent(android.view.textclassifier.SelectionEvent); method public abstract void onSuggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback); field public static final java.lang.String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService"; } @@ -5256,12 +5299,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 @@ -5429,6 +5473,7 @@ package android.telephony.euicc { public class EuiccManager { method public void continueOperation(android.content.Intent, android.os.Bundle); + method public void eraseSubscriptions(android.app.PendingIntent); method public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent); method public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent); method public int getOtaStatus(); @@ -5500,6 +5545,9 @@ package android.telephony.ims { } public final class ImsCallProfile implements android.os.Parcelable { + ctor public ImsCallProfile(); + ctor public ImsCallProfile(int, int); + ctor public ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile); method public int describeContents(); method public java.lang.String getCallExtra(java.lang.String); method public java.lang.String getCallExtra(java.lang.String, java.lang.String); @@ -5523,6 +5571,7 @@ package android.telephony.ims { method public void setCallExtraInt(java.lang.String, int); method public void updateCallExtras(android.telephony.ims.ImsCallProfile); method public void updateCallType(android.telephony.ims.ImsCallProfile); + method public void updateMediaProfile(android.telephony.ims.ImsCallProfile); method public void writeToParcel(android.os.Parcel, int); field public static final int CALL_RESTRICT_CAUSE_DISABLED = 2; // 0x2 field public static final int CALL_RESTRICT_CAUSE_HD = 3; // 0x3 @@ -5860,6 +5909,7 @@ package android.telephony.ims { } public final class ImsStreamMediaProfile implements android.os.Parcelable { + ctor public ImsStreamMediaProfile(int, int, int, int, int); method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile); method public int describeContents(); method public int getAudioDirection(); @@ -6117,19 +6167,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 getServiceFeatures(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator 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); @@ -6667,6 +6722,7 @@ package android.webkit { method public abstract android.view.View findFocus(android.view.View); method public abstract android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(); method public abstract android.os.Handler getHandler(android.os.Handler); + method public default boolean isVisibleToUserForAutofill(int); method public abstract void onActivityResult(int, int, android.content.Intent); method public abstract void onAttachedToWindow(); method public default boolean onCheckIsTextEditor(); diff --git a/api/test-current.txt b/api/test-current.txt index 9d67f4c3bb602607dd4b2943a72eb5d759f67ce1..70e3cf34f6b04be08be709d2ad56fe8cc4a0d0ed 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 { @@ -65,8 +74,8 @@ package android.app { field public static final java.lang.String OPSTR_AUDIO_NOTIFICATION_VOLUME = "android:audio_notification_volume"; field public static final java.lang.String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume"; field public static final java.lang.String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume"; - field public static final java.lang.String OPSTR_BIND_ACCESSIBILITY_SERVICE = "bind_accessibility_service"; - field public static final java.lang.String OPSTR_CHANGE_WIFI_STATE = "change_wifi_state"; + field public static final java.lang.String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service"; + field public static final java.lang.String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state"; field public static final java.lang.String OPSTR_GET_ACCOUNTS = "android:get_accounts"; field public static final java.lang.String OPSTR_GPS = "android:gps"; field public static final java.lang.String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground"; @@ -78,7 +87,7 @@ package android.app { field public static final java.lang.String OPSTR_READ_CLIPBOARD = "android:read_clipboard"; field public static final java.lang.String OPSTR_READ_ICC_SMS = "android:read_icc_sms"; field public static final java.lang.String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast"; - field public static final java.lang.String OPSTR_REQUEST_DELETE_PACKAGES = "request_delete_packages"; + field public static final java.lang.String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages"; field public static final java.lang.String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages"; field public static final java.lang.String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background"; field public static final java.lang.String OPSTR_RUN_IN_BACKGROUND = "android:run_in_background"; @@ -361,7 +370,9 @@ package android.hardware.display { public final class DisplayManager { method public java.util.List getAmbientBrightnessStats(); + method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration(); method public java.util.List getBrightnessEvents(); + method public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration(); method public android.graphics.Point getStableDisplaySize(); method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration); } @@ -464,7 +475,6 @@ package android.os { public class IncidentManager { method public void reportIncident(android.os.IncidentReportArgs); - method public void reportIncident(java.lang.String, byte[]); } public final class IncidentReportArgs implements android.os.Parcelable { @@ -475,7 +485,6 @@ package android.os { method public boolean containsSection(int); method public int describeContents(); method public boolean isAll(); - method public static android.os.IncidentReportArgs parseSetting(java.lang.String) throws java.lang.IllegalArgumentException; method public void readFromParcel(android.os.Parcel); method public int sectionCount(); method public void setAll(boolean); @@ -750,7 +759,7 @@ package android.telephony { } public class ServiceState implements android.os.Parcelable { - method public void setSystemAndNetworkId(int, int); + method public void setCdmaSystemAndNetworkId(int, int); } } diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp index 35701446e9d94e87564809e1cf2492a1a6bbb801..2b85ec08f9a6dccb17422508dc725f3ba872e670 100644 --- a/cmds/incidentd/src/FdBuffer.cpp +++ b/cmds/incidentd/src/FdBuffer.cpp @@ -34,11 +34,11 @@ FdBuffer::FdBuffer() FdBuffer::~FdBuffer() {} -status_t FdBuffer::read(int fd, int64_t timeout) { - struct pollfd pfds = {.fd = fd, .events = POLLIN}; +status_t FdBuffer::read(unique_fd* fd, int64_t timeout) { + struct pollfd pfds = {.fd = fd->get(), .events = POLLIN}; mStartTime = uptimeMillis(); - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + fcntl(fd->get(), F_SETFL, fcntl(fd->get(), F_GETFL, 0) | O_NONBLOCK); while (true) { if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) { @@ -67,16 +67,16 @@ status_t FdBuffer::read(int fd, int64_t timeout) { VLOG("return event has error %s", strerror(errno)); return errno != 0 ? -errno : UNKNOWN_ERROR; } else { - ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite()); + ssize_t amt = ::read(fd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite()); if (amt < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { continue; } else { - VLOG("Fail to read %d: %s", fd, strerror(errno)); + VLOG("Fail to read %d: %s", fd->get(), strerror(errno)); return -errno; } } else if (amt == 0) { - VLOG("Reached EOF of fd=%d", fd); + VLOG("Reached EOF of fd=%d", fd->get()); break; } mBuffer.wp()->move(amt); @@ -87,7 +87,7 @@ status_t FdBuffer::read(int fd, int64_t timeout) { return NO_ERROR; } -status_t FdBuffer::readFully(int fd) { +status_t FdBuffer::readFully(unique_fd* fd) { mStartTime = uptimeMillis(); while (true) { @@ -99,10 +99,10 @@ status_t FdBuffer::readFully(int fd) { } if (mBuffer.writeBuffer() == NULL) return NO_MEMORY; - ssize_t amt = - TEMP_FAILURE_RETRY(::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite())); + ssize_t amt = TEMP_FAILURE_RETRY( + ::read(fd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite())); if (amt < 0) { - VLOG("Fail to read %d: %s", fd, strerror(errno)); + VLOG("Fail to read %d: %s", fd->get(), strerror(errno)); return -errno; } else if (amt == 0) { VLOG("Done reading %zu bytes", mBuffer.size()); @@ -116,20 +116,20 @@ status_t FdBuffer::readFully(int fd) { return NO_ERROR; } -status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs, - const bool isSysfs) { +status_t FdBuffer::readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, unique_fd* fromFd, + int64_t timeoutMs, const bool isSysfs) { struct pollfd pfds[] = { - {.fd = fd, .events = POLLIN}, - {.fd = toFd, .events = POLLOUT}, - {.fd = fromFd, .events = POLLIN}, + {.fd = fd->get(), .events = POLLIN}, + {.fd = toFd->get(), .events = POLLOUT}, + {.fd = fromFd->get(), .events = POLLIN}, }; mStartTime = uptimeMillis(); // mark all fds non blocking - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); - fcntl(toFd, F_SETFL, fcntl(toFd, F_GETFL, 0) | O_NONBLOCK); - fcntl(fromFd, F_SETFL, fcntl(fromFd, F_GETFL, 0) | O_NONBLOCK); + fcntl(fd->get(), F_SETFL, fcntl(fd->get(), F_GETFL, 0) | O_NONBLOCK); + fcntl(toFd->get(), F_SETFL, fcntl(toFd->get(), F_GETFL, 0) | O_NONBLOCK); + fcntl(fromFd->get(), F_SETFL, fcntl(fromFd->get(), F_GETFL, 0) | O_NONBLOCK); // A circular buffer holds data read from fd and writes to parsing process uint8_t cirBuf[BUFFER_SIZE]; @@ -166,10 +166,10 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64 for (int i = 0; i < 3; ++i) { if ((pfds[i].revents & POLLERR) != 0) { if (i == 0 && isSysfs) { - VLOG("fd %d is sysfs, ignore its POLLERR return value", fd); + VLOG("fd %d is sysfs, ignore its POLLERR return value", fd->get()); continue; } - VLOG("fd[%d]=%d returns error events: %s", i, fd, strerror(errno)); + VLOG("fd[%d]=%d returns error events: %s", i, fd->get(), strerror(errno)); return errno != 0 ? -errno : UNKNOWN_ERROR; } } @@ -178,17 +178,17 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64 if (cirSize != BUFFER_SIZE && pfds[0].fd != -1) { ssize_t amt; if (rpos >= wpos) { - amt = ::read(fd, cirBuf + rpos, BUFFER_SIZE - rpos); + amt = ::read(fd->get(), cirBuf + rpos, BUFFER_SIZE - rpos); } else { - amt = ::read(fd, cirBuf + rpos, wpos - rpos); + amt = ::read(fd->get(), cirBuf + rpos, wpos - rpos); } if (amt < 0) { if (!(errno == EAGAIN || errno == EWOULDBLOCK)) { - VLOG("Fail to read fd %d: %s", fd, strerror(errno)); + VLOG("Fail to read fd %d: %s", fd->get(), strerror(errno)); return -errno; } // otherwise just continue } else if (amt == 0) { - VLOG("Reached EOF of input file %d", fd); + VLOG("Reached EOF of input file %d", fd->get()); pfds[0].fd = -1; // reach EOF so don't have to poll pfds[0]. } else { rpos += amt; @@ -200,13 +200,13 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64 if (cirSize > 0 && pfds[1].fd != -1) { ssize_t amt; if (rpos > wpos) { - amt = ::write(toFd, cirBuf + wpos, rpos - wpos); + amt = ::write(toFd->get(), cirBuf + wpos, rpos - wpos); } else { - amt = ::write(toFd, cirBuf + wpos, BUFFER_SIZE - wpos); + amt = ::write(toFd->get(), cirBuf + wpos, BUFFER_SIZE - wpos); } if (amt < 0) { if (!(errno == EAGAIN || errno == EWOULDBLOCK)) { - VLOG("Fail to write toFd %d: %s", toFd, strerror(errno)); + VLOG("Fail to write toFd %d: %s", toFd->get(), strerror(errno)); return -errno; } // otherwise just continue } else { @@ -217,8 +217,8 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64 // if buffer is empty and fd is closed, close write fd. if (cirSize == 0 && pfds[0].fd == -1 && pfds[1].fd != -1) { - VLOG("Close write pipe %d", toFd); - ::close(pfds[1].fd); + VLOG("Close write pipe %d", toFd->get()); + toFd->reset(); pfds[1].fd = -1; } @@ -231,14 +231,14 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64 } // read from parsing process - ssize_t amt = ::read(fromFd, mBuffer.writeBuffer(), mBuffer.currentToWrite()); + ssize_t amt = ::read(fromFd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite()); if (amt < 0) { if (!(errno == EAGAIN || errno == EWOULDBLOCK)) { - VLOG("Fail to read fromFd %d: %s", fromFd, strerror(errno)); + VLOG("Fail to read fromFd %d: %s", fromFd->get(), strerror(errno)); return -errno; } // otherwise just continue } else if (amt == 0) { - VLOG("Reached EOF of fromFd %d", fromFd); + VLOG("Reached EOF of fromFd %d", fromFd->get()); break; } else { mBuffer.wp()->move(amt); diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h index 34ebcf50905dee616b90b903c6fd70850f885585..db3a74b7817821fe9be60cf81eb18b426846f4c3 100644 --- a/cmds/incidentd/src/FdBuffer.h +++ b/cmds/incidentd/src/FdBuffer.h @@ -18,10 +18,12 @@ #ifndef FD_BUFFER_H #define FD_BUFFER_H +#include #include #include using namespace android; +using namespace android::base; using namespace android::util; using namespace std; @@ -38,13 +40,13 @@ public: * Returns NO_ERROR if there were no errors or if we timed out. * Will mark the file O_NONBLOCK. */ - status_t read(int fd, int64_t timeoutMs); + status_t read(unique_fd* fd, int64_t timeoutMs); /** * Read the data until we hit eof. * Returns NO_ERROR if there were no errors. */ - status_t readFully(int fd); + status_t readFully(unique_fd* fd); /** * Read processed results by streaming data to a parsing process, e.g. incident helper. @@ -56,8 +58,8 @@ public: * * Poll will return POLLERR if fd is from sysfs, handle this edge case. */ - status_t readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs, - const bool isSysfs = false); + status_t readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, unique_fd* fromFd, + int64_t timeoutMs, const bool isSysfs = false); /** * Whether we timed out. diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp index d02b4dd99067ea69b41553b6cac483dd821c8026..aeccefdd15c0dbb9c23c5432dd76d4c6526248b3 100644 --- a/cmds/incidentd/src/IncidentService.cpp +++ b/cmds/incidentd/src/IncidentService.cpp @@ -352,7 +352,8 @@ status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vectorname.string()); return -errno; } @@ -299,9 +299,8 @@ status_t FileSection::Execute(ReportRequestSet* requests) const { } // parent process - status_t readStatus = buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(), c2pPipe.readFd(), - this->timeoutMs, mIsSysfs); - close(fd); // close the fd anyway. + status_t readStatus = buffer.readProcessedDataInStream( + &fd, &p2cPipe.writeFd(), &c2pPipe.readFd(), this->timeoutMs, mIsSysfs); if (readStatus != NO_ERROR || buffer.timedOut()) { ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s", @@ -342,17 +341,17 @@ GZipSection::~GZipSection() {} status_t GZipSection::Execute(ReportRequestSet* requests) const { // Reads the files in order, use the first available one. int index = 0; - int fd = -1; + unique_fd fd; while (mFilenames[index] != NULL) { - fd = open(mFilenames[index], O_RDONLY | O_CLOEXEC); - if (fd != -1) { + fd.reset(open(mFilenames[index], O_RDONLY | O_CLOEXEC)); + if (fd.get() != -1) { break; } ALOGW("GZipSection failed to open file %s", mFilenames[index]); index++; // look at the next file. } - VLOG("GZipSection is using file %s, fd=%d", mFilenames[index], fd); - if (fd == -1) return -1; + VLOG("GZipSection is using file %s, fd=%d", mFilenames[index], fd.get()); + if (fd.get() == -1) return -1; FdBuffer buffer; Fpipe p2cPipe; @@ -388,9 +387,9 @@ status_t GZipSection::Execute(ReportRequestSet* requests) const { VLOG("GZipSection '%s' editPos=%zd, dataBeginAt=%zd", this->name.string(), editPos, dataBeginAt); - status_t readStatus = buffer.readProcessedDataInStream( - fd, p2cPipe.writeFd(), c2pPipe.readFd(), this->timeoutMs, isSysfs(mFilenames[index])); - close(fd); // close the fd anyway. + status_t readStatus = + buffer.readProcessedDataInStream(&fd, &p2cPipe.writeFd(), &c2pPipe.readFd(), + this->timeoutMs, isSysfs(mFilenames[index])); if (readStatus != NO_ERROR || buffer.timedOut()) { ALOGW("GZipSection '%s' failed to read data from gzip: %s, timedout: %s", @@ -424,7 +423,7 @@ status_t GZipSection::Execute(ReportRequestSet* requests) const { // ================================================================================ struct WorkerThreadData : public virtual RefBase { const WorkerThreadSection* section; - int fds[2]; + Fpipe pipe; // Lock protects these fields mutex lock; @@ -433,16 +432,10 @@ struct WorkerThreadData : public virtual RefBase { WorkerThreadData(const WorkerThreadSection* section); virtual ~WorkerThreadData(); - - int readFd() { return fds[0]; } - int writeFd() { return fds[1]; } }; WorkerThreadData::WorkerThreadData(const WorkerThreadSection* sec) - : section(sec), workerDone(false), workerError(NO_ERROR) { - fds[0] = -1; - fds[1] = -1; -} + : section(sec), workerDone(false), workerError(NO_ERROR) {} WorkerThreadData::~WorkerThreadData() {} @@ -454,7 +447,7 @@ WorkerThreadSection::~WorkerThreadSection() {} static void* worker_thread_func(void* cookie) { WorkerThreadData* data = (WorkerThreadData*)cookie; - status_t err = data->section->BlockingCall(data->writeFd()); + status_t err = data->section->BlockingCall(data->pipe.writeFd().get()); { unique_lock lock(data->lock); @@ -462,7 +455,7 @@ static void* worker_thread_func(void* cookie) { data->workerError = err; } - close(data->writeFd()); + data->pipe.writeFd().reset(); data->decStrong(data->section); // data might be gone now. don't use it after this point in this thread. return NULL; @@ -479,8 +472,7 @@ status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const { sp data = new WorkerThreadData(this); // Create the pipe - err = pipe(data->fds); - if (err != 0) { + if (!data->pipe.init()) { return -errno; } @@ -507,7 +499,7 @@ status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const { pthread_attr_destroy(&attr); // Loop reading until either the timeout or the worker side is done (i.e. eof). - err = buffer.read(data->readFd(), this->timeoutMs); + err = buffer.read(&data->pipe.readFd(), this->timeoutMs); if (err != NO_ERROR) { // TODO: Log this error into the incident report. ALOGW("WorkerThreadSection '%s' reader failed with error '%s'", this->name.string(), @@ -516,7 +508,7 @@ status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const { // Done with the read fd. The worker thread closes the write one so // we never race and get here first. - close(data->readFd()); + data->pipe.readFd().reset(); // If the worker side is finished, then return its error (which may overwrite // our possible error -- but it's more interesting anyway). If not, then we timed out. @@ -602,7 +594,8 @@ status_t CommandSection::Execute(ReportRequestSet* requests) const { // child process to execute the command as root if (cmdPid == 0) { // replace command's stdout with ihPipe's write Fd - if (dup2(cmdPipe.writeFd(), STDOUT_FILENO) != 1 || !ihPipe.close() || !cmdPipe.close()) { + if (dup2(cmdPipe.writeFd().get(), STDOUT_FILENO) != 1 || !ihPipe.close() || + !cmdPipe.close()) { ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(), strerror(errno)); _exit(EXIT_FAILURE); @@ -619,8 +612,8 @@ status_t CommandSection::Execute(ReportRequestSet* requests) const { return -errno; } - close(cmdPipe.writeFd()); - status_t readStatus = buffer.read(ihPipe.readFd(), this->timeoutMs); + cmdPipe.writeFd().reset(); + status_t readStatus = buffer.read(&ihPipe.readFd(), this->timeoutMs); if (readStatus != NO_ERROR || buffer.timedOut()) { ALOGW("CommandSection '%s' failed to read data from incident helper: %s, timedout: %s", this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false"); @@ -738,25 +731,25 @@ status_t LogSection::BlockingCall(int pipeWriteFd) const { android_logger_list_free); if (android_logger_open(loggers.get(), mLogID) == NULL) { - ALOGW("LogSection %s: Can't get logger.", this->name.string()); - return NO_ERROR; + ALOGE("LogSection %s: Can't get logger.", this->name.string()); + return -1; } log_msg msg; log_time lastTimestamp(0); - status_t err = NO_ERROR; ProtoOutputStream proto; while (true) { // keeps reading until logd buffer is fully read. - err = android_logger_list_read(loggers.get(), &msg); + status_t err = android_logger_list_read(loggers.get(), &msg); // err = 0 - no content, unexpected connection drop or EOF. // err = +ive number - size of retrieved data from logger // err = -ive number, OS supplied error _except_ for -EAGAIN // err = -EAGAIN, graceful indication for ANDRODI_LOG_NONBLOCK that this is the end of data. if (err <= 0) { if (err != -EAGAIN) { - ALOGE("LogSection %s: fails to read a log_msg.\n", this->name.string()); + ALOGW("LogSection %s: fails to read a log_msg.\n", this->name.string()); } + // dump previous logs and don't consider this error a failure. break; } if (mBinary) { @@ -825,7 +818,7 @@ status_t LogSection::BlockingCall(int pipeWriteFd) const { AndroidLogEntry entry; err = android_log_processLogBuffer(&msg.entry_v1, &entry); if (err != NO_ERROR) { - ALOGE("LogSection %s: fails to process to an entry.\n", this->name.string()); + ALOGW("LogSection %s: fails to process to an entry.\n", this->name.string()); break; } lastTimestamp.tv_sec = entry.tv_sec; @@ -847,7 +840,7 @@ status_t LogSection::BlockingCall(int pipeWriteFd) const { } gLastLogsRetrieved[mLogID] = lastTimestamp; proto.flush(pipeWriteFd); - return err; + return NO_ERROR; } // ================================================================================ @@ -921,10 +914,10 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const { break; } else if (child == 0) { // This is the child process. - close(dumpPipe.readFd()); + dumpPipe.readFd().reset(); const int ret = dump_backtrace_to_file_timeout( pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace, - is_java_process ? 5 : 20, dumpPipe.writeFd()); + is_java_process ? 5 : 20, dumpPipe.writeFd().get()); if (ret == -1) { if (errno == 0) { ALOGW("Dumping failed for pid '%d', likely due to a timeout\n", pid); @@ -932,25 +925,17 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const { ALOGE("Dumping failed for pid '%d': %s\n", pid, strerror(errno)); } } - if (close(dumpPipe.writeFd()) != 0) { - ALOGW("TombstoneSection '%s' failed to close dump pipe writeFd: %d", - this->name.string(), errno); - _exit(EXIT_FAILURE); - } - + dumpPipe.writeFd().reset(); _exit(EXIT_SUCCESS); } - close(dumpPipe.writeFd()); + dumpPipe.writeFd().reset(); // Parent process. // Read from the pipe concurrently to avoid blocking the child. FdBuffer buffer; - err = buffer.readFully(dumpPipe.readFd()); + err = buffer.readFully(&dumpPipe.readFd()); if (err != NO_ERROR) { ALOGW("TombstoneSection '%s' failed to read stack dump: %d", this->name.string(), err); - if (close(dumpPipe.readFd()) != 0) { - ALOGW("TombstoneSection '%s' failed to close dump pipe readFd: %s", - this->name.string(), strerror(errno)); - } + dumpPipe.readFd().reset(); break; } @@ -967,13 +952,7 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const { proto.write(android::os::BackTraceProto::Stack::DUMP_DURATION_NS, static_cast(Nanotime() - start)); proto.end(token); - - if (close(dumpPipe.readFd()) != 0) { - ALOGW("TombstoneSection '%s' failed to close dump pipe readFd: %d", this->name.string(), - errno); - err = -errno; - break; - } + dumpPipe.readFd().reset(); } proto.flush(pipeWriteFd); diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp index c869c7a8d1d4cafbb9c6acb6343bd173ad6e9c01..d7995133c7223c9c6649a8b8b2af731dc561b048 100644 --- a/cmds/incidentd/src/incidentd_util.cpp +++ b/cmds/incidentd/src/incidentd_util.cpp @@ -53,16 +53,17 @@ bool Fpipe::close() { bool Fpipe::init() { return Pipe(&mRead, &mWrite); } -int Fpipe::readFd() const { return mRead.get(); } +unique_fd& Fpipe::readFd() { return mRead; } -int Fpipe::writeFd() const { return mWrite.get(); } +unique_fd& Fpipe::writeFd() { return mWrite; } pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe* output) { // fork used in multithreaded environment, avoid adding unnecessary code in child process pid_t pid = fork(); if (pid == 0) { - if (TEMP_FAILURE_RETRY(dup2(input->readFd(), STDIN_FILENO)) < 0 || !input->close() || - TEMP_FAILURE_RETRY(dup2(output->writeFd(), STDOUT_FILENO)) < 0 || !output->close()) { + if (TEMP_FAILURE_RETRY(dup2(input->readFd().get(), STDIN_FILENO)) < 0 || !input->close() || + TEMP_FAILURE_RETRY(dup2(output->writeFd().get(), STDOUT_FILENO)) < 0 || + !output->close()) { ALOGW("Can't setup stdin and stdout for command %s", cmd); _exit(EXIT_FAILURE); } @@ -76,8 +77,8 @@ pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe* _exit(EXIT_FAILURE); // always exits with failure if any } // close the fds used in child process. - close(input->readFd()); - close(output->writeFd()); + input->readFd().reset(); + output->writeFd().reset(); return pid; } diff --git a/cmds/incidentd/src/incidentd_util.h b/cmds/incidentd/src/incidentd_util.h index 3f7df91e7e50411d8986e31cabc05412d72a9e83..228d7762fc81f6ce7cd9e8e6d2cf58c24d9ab07d 100644 --- a/cmds/incidentd/src/incidentd_util.h +++ b/cmds/incidentd/src/incidentd_util.h @@ -41,8 +41,8 @@ public: bool init(); bool close(); - int readFd() const; - int writeFd() const; + unique_fd& readFd(); + unique_fd& writeFd(); private: unique_fd mRead; diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp index 0e5eec6c702302586dad59b308a188348baad7b7..bf770173793f1284e868e0cdb1bd1f75d2392738 100644 --- a/cmds/incidentd/tests/FdBuffer_test.cpp +++ b/cmds/incidentd/tests/FdBuffer_test.cpp @@ -37,6 +37,7 @@ class FdBufferTest : public Test { public: virtual void SetUp() override { ASSERT_NE(tf.fd, -1); + tffd.reset(tf.fd); ASSERT_NE(p2cPipe.init(), -1); ASSERT_NE(c2pPipe.init(), -1); } @@ -56,13 +57,13 @@ public: EXPECT_EQ(expected[i], '\0'); } - bool DoDataStream(int rFd, int wFd) { + bool DoDataStream(unique_fd* rFd, unique_fd* wFd) { char buf[BUFFER_SIZE]; ssize_t nRead; - while ((nRead = read(rFd, buf, BUFFER_SIZE)) > 0) { + while ((nRead = read(rFd->get(), buf, BUFFER_SIZE)) > 0) { ssize_t nWritten = 0; while (nWritten < nRead) { - ssize_t amt = write(wFd, buf + nWritten, nRead - nWritten); + ssize_t amt = write(wFd->get(), buf + nWritten, nRead - nWritten); if (amt < 0) { return false; } @@ -75,6 +76,7 @@ public: protected: FdBuffer buffer; TemporaryFile tf; + unique_fd tffd; Fpipe p2cPipe; Fpipe c2pPipe; @@ -85,7 +87,7 @@ protected: TEST_F(FdBufferTest, ReadAndWrite) { std::string testdata = "FdBuffer test string"; ASSERT_TRUE(WriteStringToFile(testdata, tf.path)); - ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, buffer.read(&tffd, READ_TIMEOUT)); AssertBufferReadSuccessful(testdata.size()); AssertBufferContent(testdata.c_str()); } @@ -98,7 +100,7 @@ TEST_F(FdBufferTest, IterateEmpty) { TEST_F(FdBufferTest, ReadAndIterate) { std::string testdata = "FdBuffer test string"; ASSERT_TRUE(WriteStringToFile(testdata, tf.path)); - ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, buffer.read(&tffd, READ_TIMEOUT)); int i = 0; EncodedBuffer::iterator it = buffer.data(); @@ -117,16 +119,16 @@ TEST_F(FdBufferTest, ReadTimeout) { ASSERT_TRUE(pid != -1); if (pid == 0) { - close(c2pPipe.readFd()); + c2pPipe.readFd().reset(); while (true) { write(c2pPipe.writeFd(), "poo", 3); sleep(1); } _exit(EXIT_FAILURE); } else { - close(c2pPipe.writeFd()); + c2pPipe.writeFd().reset(); - status_t status = buffer.read(c2pPipe.readFd(), QUICK_TIMEOUT_MS); + status_t status = buffer.read(&c2pPipe.readFd(), QUICK_TIMEOUT_MS); ASSERT_EQ(NO_ERROR, status); EXPECT_TRUE(buffer.timedOut()); @@ -143,20 +145,20 @@ TEST_F(FdBufferTest, ReadInStreamAndWrite) { ASSERT_TRUE(pid != -1); if (pid == 0) { - close(p2cPipe.writeFd()); - close(c2pPipe.readFd()); + p2cPipe.writeFd().reset(); + c2pPipe.readFd().reset(); ASSERT_TRUE(WriteStringToFd(HEAD, c2pPipe.writeFd())); - ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd())); - close(p2cPipe.readFd()); - close(c2pPipe.writeFd()); + ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd())); + p2cPipe.readFd().reset(); + c2pPipe.writeFd().reset(); // Must exit here otherwise the child process will continue executing the test binary. _exit(EXIT_SUCCESS); } else { - close(p2cPipe.readFd()); - close(c2pPipe.writeFd()); + p2cPipe.readFd().reset(); + c2pPipe.writeFd().reset(); - ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(), - c2pPipe.readFd(), READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(), + &c2pPipe.readFd(), READ_TIMEOUT)); AssertBufferReadSuccessful(HEAD.size() + testdata.size()); AssertBufferContent(expected.c_str()); wait(&pid); @@ -172,23 +174,23 @@ TEST_F(FdBufferTest, ReadInStreamAndWriteAllAtOnce) { ASSERT_TRUE(pid != -1); if (pid == 0) { - close(p2cPipe.writeFd()); - close(c2pPipe.readFd()); + p2cPipe.writeFd().reset(); + c2pPipe.readFd().reset(); std::string data; // wait for read finishes then write. ASSERT_TRUE(ReadFdToString(p2cPipe.readFd(), &data)); data = HEAD + data; ASSERT_TRUE(WriteStringToFd(data, c2pPipe.writeFd())); - close(p2cPipe.readFd()); - close(c2pPipe.writeFd()); + p2cPipe.readFd().reset(); + c2pPipe.writeFd().reset(); // Must exit here otherwise the child process will continue executing the test binary. _exit(EXIT_SUCCESS); } else { - close(p2cPipe.readFd()); - close(c2pPipe.writeFd()); + p2cPipe.readFd().reset(); + c2pPipe.writeFd().reset(); - ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(), - c2pPipe.readFd(), READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(), + &c2pPipe.readFd(), READ_TIMEOUT)); AssertBufferReadSuccessful(HEAD.size() + testdata.size()); AssertBufferContent(expected.c_str()); wait(&pid); @@ -202,18 +204,18 @@ TEST_F(FdBufferTest, ReadInStreamEmpty) { ASSERT_TRUE(pid != -1); if (pid == 0) { - close(p2cPipe.writeFd()); - close(c2pPipe.readFd()); - ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd())); - close(p2cPipe.readFd()); - close(c2pPipe.writeFd()); + p2cPipe.writeFd().reset(); + c2pPipe.readFd().reset(); + ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd())); + p2cPipe.readFd().reset(); + c2pPipe.writeFd().reset(); _exit(EXIT_SUCCESS); } else { - close(p2cPipe.readFd()); - close(c2pPipe.writeFd()); + p2cPipe.readFd().reset(); + c2pPipe.writeFd().reset(); - ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(), - c2pPipe.readFd(), READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(), + &c2pPipe.readFd(), READ_TIMEOUT)); AssertBufferReadSuccessful(0); AssertBufferContent(""); wait(&pid); @@ -223,24 +225,24 @@ TEST_F(FdBufferTest, ReadInStreamEmpty) { TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) { const std::string testFile = kTestDataPath + "morethan4MB.txt"; size_t fourMB = (size_t)4 * 1024 * 1024; - int fd = open(testFile.c_str(), O_RDONLY | O_CLOEXEC); - ASSERT_NE(fd, -1); + unique_fd fd(open(testFile.c_str(), O_RDONLY | O_CLOEXEC)); + ASSERT_NE(fd.get(), -1); int pid = fork(); ASSERT_TRUE(pid != -1); if (pid == 0) { - close(p2cPipe.writeFd()); - close(c2pPipe.readFd()); - ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd())); - close(p2cPipe.readFd()); - close(c2pPipe.writeFd()); + p2cPipe.writeFd().reset(); + c2pPipe.readFd().reset(); + ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd())); + p2cPipe.readFd().reset(); + c2pPipe.writeFd().reset(); _exit(EXIT_SUCCESS); } else { - close(p2cPipe.readFd()); - close(c2pPipe.writeFd()); + p2cPipe.readFd().reset(); + c2pPipe.writeFd().reset(); - ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(), - c2pPipe.readFd(), READ_TIMEOUT)); + ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&fd, &p2cPipe.writeFd(), + &c2pPipe.readFd(), READ_TIMEOUT)); EXPECT_EQ(buffer.size(), fourMB); EXPECT_FALSE(buffer.timedOut()); EXPECT_TRUE(buffer.truncated()); @@ -266,18 +268,18 @@ TEST_F(FdBufferTest, ReadInStreamTimeOut) { ASSERT_TRUE(pid != -1); if (pid == 0) { - close(p2cPipe.writeFd()); - close(c2pPipe.readFd()); + p2cPipe.writeFd().reset(); + c2pPipe.readFd().reset(); while (true) { sleep(1); } _exit(EXIT_FAILURE); } else { - close(p2cPipe.readFd()); - close(c2pPipe.writeFd()); + p2cPipe.readFd().reset(); + c2pPipe.writeFd().reset(); - ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(), - c2pPipe.readFd(), QUICK_TIMEOUT_MS)); + ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(), + &c2pPipe.readFd(), QUICK_TIMEOUT_MS)); EXPECT_TRUE(buffer.timedOut()); kill(pid, SIGKILL); // reap the child process } diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp index c7c69a746f0ac3bf6055915fce679d29db254b8c..5edc0c79785b38de0a54e426cc5cc2b94e7b1043 100644 --- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp +++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp @@ -58,7 +58,8 @@ public: void writeToFdBuffer(string str) { ASSERT_TRUE(WriteStringToFile(str, tf.path)); - ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, 10000)); + unique_fd tffd(tf.fd); + ASSERT_EQ(NO_ERROR, buffer.read(&tffd, 10000)); ASSERT_EQ(str.size(), buffer.size()); } diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 7f0a26c1714ea47f0fa006620bbf040ff981ff45..ca0611b0ca057ddc92ab89bdf59a7694d3ec63f4 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -17,7 +17,6 @@ LOCAL_PATH:= $(call my-dir) statsd_common_src := \ ../../core/java/android/os/IStatsCompanionService.aidl \ ../../core/java/android/os/IStatsManager.aidl \ - src/stats_log_common.proto \ src/statsd_config.proto \ src/FieldValue.cpp \ src/stats_log_util.cpp \ @@ -82,10 +81,8 @@ statsd_common_static_libraries := \ statsd_common_shared_libraries := \ libbase \ libbinder \ - libcutils \ libincident \ liblog \ - libselinux \ libutils \ libservices \ libprotoutil \ @@ -180,6 +177,7 @@ LOCAL_SRC_FILES := \ tests/LogEvent_test.cpp \ tests/MetricsManager_test.cpp \ tests/StatsLogProcessor_test.cpp \ + tests/StatsService_test.cpp \ tests/UidMap_test.cpp \ tests/FieldValue_test.cpp \ tests/condition/CombinationConditionTracker_test.cpp \ @@ -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 @@ -226,7 +224,6 @@ LOCAL_MODULE := statsdprotolite LOCAL_SRC_FILES := \ src/stats_log.proto \ - src/stats_log_common.proto \ src/statsd_config.proto \ src/perfetto/perfetto_config.proto \ src/atoms.proto @@ -308,4 +305,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 66c4defe7adb8f33cfeea53d89e4dbc64a56f266..cfe477d7ca8f99868f9baa9160464308939ed734 100644 --- a/cmds/statsd/benchmark/filter_value_benchmark.cpp +++ b/cmds/statsd/benchmark/filter_value_benchmark.cpp @@ -53,29 +53,13 @@ static void BM_FilterValue(benchmark::State& state) { std::vector matchers; translateFieldMatcher(field_matcher, &matchers); - while (state.KeepRunning()) { - vector 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 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 0c9b7016eaff1a971f145ac48a65087341c4e1ca..dfd8705f83aa3e1e88e98ef0f6f5b0b577b42656 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 0e3ae06033e75c3efc8e2e57309937e3009ff59b..f7ce23b04339b7bce5ad7b19db568c15ad8ffa3f 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 d0c83119dc43e66337a303169ee0ffaf21fccdb1..71030345b0aa455e3f90a88b783dcfe4d114a7a4 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& matcherFields, const vector& 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 -bool filterValues(const vector& matcherFields, const vector& values, - vector* 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 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& matcherFields, diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h index 4cfed883ec0753e2ae7d0b046c3c869be65b355c..6f4941f717eedeec98e25e0b712602ca2b87c947 100644 --- a/cmds/statsd/src/HashableDimensionKey.h +++ b/cmds/statsd/src/HashableDimensionKey.h @@ -122,16 +122,13 @@ 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& matcherFields, const std::vector& values, - std::vector* output); -// This function is used when there is at most one output dimension key. (no ANY matcher) bool filterValues(const std::vector& matcherFields, const std::vector& values, HashableDimensionKey* output); diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 02d4dc985e84cc4c6532087bc5b0d26a965f07a1..82274a6e4c597d8ab1328cd6bef87d7bc4f054dc 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" @@ -109,8 +112,8 @@ void updateUid(Value* value, int hostUid) { } void StatsLogProcessor::mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const { - if (android::util::kAtomsWithAttributionChain.find(event->GetTagId()) != - android::util::kAtomsWithAttributionChain.end()) { + if (android::util::AtomsInfo::kAtomsWithAttributionChain.find(event->GetTagId()) != + android::util::AtomsInfo::kAtomsWithAttributionChain.end()) { for (auto& value : *(event->getMutableValues())) { if (value.mField.getPosAtDepth(0) > kAttributionField) { break; @@ -120,12 +123,20 @@ void StatsLogProcessor::mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event updateUid(&value.mValue, hostUid); } } - } else if (android::util::kAtomsWithUidField.find(event->GetTagId()) != - android::util::kAtomsWithUidField.end() && - event->getValues().size() > 0 && (event->getValues())[0].mValue.getType() == INT) { - Value& value = (*event->getMutableValues())[0].mValue; - const int hostUid = mUidMap->getHostUidOrSelf(value.int_value); - updateUid(&value, hostUid); + } else { + auto it = android::util::AtomsInfo::kAtomsWithUidField.find(event->GetTagId()); + if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) { + int uidField = it->second; // uidField is the field number in proto, + // starting from 1 + if (uidField > 0 && (int)event->getValues().size() >= uidField && + (event->getValues())[uidField - 1].mValue.getType() == INT) { + Value& value = (*event->getMutableValues())[uidField - 1].mValue; + const int hostUid = mUidMap->getHostUidOrSelf(value.int_value); + updateUid(&value, hostUid); + } else { + ALOGE("Malformed log, uid not found. %s", event->ToString().c_str()); + } + } } } @@ -228,14 +239,13 @@ void StatsLogProcessor::dumpStates(FILE* out, bool verbose) { } } +/* + * onDumpReport dumps serialized ConfigMetricsReportList into outData. + */ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const uint64_t dumpTimeStampNs, vector* outData) { std::lock_guard lock(mMetricsMutex); - onDumpReportLocked(key, dumpTimeStampNs, outData); -} -void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeStampNs, - vector* outData) { auto it = mMetricsManagers.find(key); if (it == mMetricsManagers.end()) { ALOGW("Config source %s does not exist", key.ToString().c_str()); @@ -258,31 +268,14 @@ void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t // Start of ConfigMetricsReport (reports). uint64_t reportsToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS); - - int64_t lastReportTimeNs = it->second->getLastReportTimeNs(); - // First, fill in ConfigMetricsReport using current data on memory, which - // starts from filling in StatsLogReport's. - it->second->onDumpReport(dumpTimeStampNs, &proto); - - // Fill in UidMap. - auto uidMap = mUidMap->getOutput(key); - const int uidMapSize = uidMap.ByteSize(); - char uidMapBuffer[uidMapSize]; - uidMap.SerializeToArray(&uidMapBuffer[0], uidMapSize); - proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMapBuffer, uidMapSize); - - // Fill in the timestamps. - proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS, - (long long)lastReportTimeNs); - proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS, - (long long)dumpTimeStampNs); - - // End of ConfigMetricsReport (reports). + onConfigMetricsReportLocked(key, dumpTimeStampNs, &proto); proto.end(reportsToken); + // End of ConfigMetricsReport (reports). + // Then, check stats-data directory to see there's any file containing // ConfigMetricsReport from previous shutdowns to concatenate to reports. - StorageManager::appendConfigMetricsReport(proto); + StorageManager::appendConfigMetricsReport(key, &proto); if (outData != nullptr) { outData->clear(); @@ -300,6 +293,40 @@ void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t StatsdStats::getInstance().noteMetricsReportSent(key); } +/* + * onConfigMetricsReportLocked dumps serialized ConfigMetricsReport into outData. + */ +void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key, + const uint64_t dumpTimeStampNs, + ProtoOutputStream* proto) { + // We already checked whether key exists in mMetricsManagers in + // WriteDataToDisk. + auto it = mMetricsManagers.find(key); + 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); + + // Fill in UidMap. + uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP); + mUidMap->appendUidMap(key, proto); + proto->end(uidMapToken); + + // Fill in the timestamps. + proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS, + (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()); + + +} + void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) { std::lock_guard lock(mMetricsMutex); auto it = mMetricsManagers.find(key); @@ -353,11 +380,17 @@ void StatsLogProcessor::WriteDataToDisk() { std::lock_guard lock(mMetricsMutex); for (auto& pair : mMetricsManagers) { const ConfigKey& key = pair.first; - vector data; - onDumpReportLocked(key, getElapsedRealtimeNs(), &data); + ProtoOutputStream proto; + onConfigMetricsReportLocked(key, getElapsedRealtimeNs(), &proto); string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR, (long)getWallClockSec(), key.GetUid(), (long long)key.GetId()); - StorageManager::writeFile(file_name.c_str(), &data[0], data.size()); + android::base::unique_fd fd(open(file_name.c_str(), + O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR)); + if (fd == -1) { + VLOG("Attempt to write %s but failed", file_name.c_str()); + return; + } + proto.flush(fd.get()); } } diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 8db82006d082f80a73ae02e0153a1798c801fdf8..1be4dc5d58c72c558d2790ad20ada2fbf3043d5b 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -86,8 +86,8 @@ private: sp mPeriodicAlarmMonitor; - void onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeNs, - vector* outData); + void onConfigMetricsReportLocked(const ConfigKey& key, const uint64_t dumpTimeStampNs, + util::ProtoOutputStream* proto); /* Check if we should send a broadcast if approaching memory limits and if we're over, we * actually delete the data. */ @@ -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/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index c5dfc4488c1b9730333192ee3086b168c5be719a..b86646a32ac8da09b9210b57505642b6cae8e4d3 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -867,14 +867,11 @@ Status StatsService::addConfiguration(int64_t key, bool* success) { IPCThreadState* ipc = IPCThreadState::self(); if (checkCallingPermission(String16(kPermissionDump))) { - ConfigKey configKey(ipc->getCallingUid(), key); - StatsdConfig cfg; - if (config.empty() || !cfg.ParseFromArray(&config[0], config.size())) { + if (addConfigurationChecked(ipc->getCallingUid(), key, config)) { + *success = true; + } else { *success = false; - return Status::ok(); } - mConfigManager->UpdateConfig(configKey, cfg); - *success = true; return Status::ok(); } else { *success = false; @@ -882,6 +879,18 @@ Status StatsService::addConfiguration(int64_t key, } } +bool StatsService::addConfigurationChecked(int uid, int64_t key, const vector& config) { + ConfigKey configKey(uid, key); + StatsdConfig cfg; + if (config.size() > 0) { // If the config is empty, skip parsing. + if (!cfg.ParseFromArray(&config[0], config.size())) { + return false; + } + } + mConfigManager->UpdateConfig(configKey, cfg); + return true; +} + Status StatsService::removeDataFetchOperation(int64_t key, bool* success) { IPCThreadState* ipc = IPCThreadState::self(); if (checkCallingPermission(String16(kPermissionDump))) { diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 02b61244b3bbbd4c152be474e5da9a7dc08c3e56..0ec31ef81c945dbd5282e7d4b265241498dc568b 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -17,6 +17,7 @@ #ifndef STATS_SERVICE_H #define STATS_SERVICE_H +#include #include "StatsLogProcessor.h" #include "anomaly/AlarmMonitor.h" #include "config/ConfigManager.h" @@ -215,6 +216,11 @@ private: */ status_t cmd_clear_puller_cache(FILE* out); + /** + * Adds a configuration after checking permissions and obtaining UID from binder call. + */ + bool addConfigurationChecked(int uid, int64_t key, const vector& config); + /** * Update a configuration. */ @@ -254,6 +260,10 @@ private: * Whether this is an eng build. */ bool mEngBuild; + + FRIEND_TEST(StatsServiceTest, TestAddConfig_simple); + FRIEND_TEST(StatsServiceTest, TestAddConfig_empty); + FRIEND_TEST(StatsServiceTest, TestAddConfig_invalid); }; } // namespace statsd diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp index 133f33b15405e0b16fc8a6a3c1c17d5fe07be780..49de1ac417bc76949d889dfc939b5d11d48741a0 100644 --- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp +++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp @@ -31,9 +31,8 @@ namespace android { namespace os { namespace statsd { -// TODO: Get rid of bucketNumbers, and return to the original circular array method. AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey) - : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) { + : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) { VLOG("AnomalyTracker() called"); if (mAlert.num_buckets() <= 0) { ALOGE("Cannot create AnomalyTracker with %lld buckets", (long long)mAlert.num_buckets()); @@ -60,85 +59,102 @@ void AnomalyTracker::resetStorage() { size_t AnomalyTracker::index(int64_t bucketNum) const { if (bucketNum < 0) { - // To support this use-case, we can easily modify index to wrap around. But currently - // AnomalyTracker should never need this, so if it happens, it's a bug we should log. - // TODO: Audit this. ALOGE("index() was passed a negative bucket number (%lld)!", (long long)bucketNum); } return bucketNum % mNumOfPastBuckets; } -void AnomalyTracker::flushPastBuckets(const int64_t& latestPastBucketNum) { - VLOG("addPastBucket() called."); - if (latestPastBucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) { - ALOGE("Cannot add a past bucket %lld units in past", (long long)latestPastBucketNum); +void AnomalyTracker::advanceMostRecentBucketTo(const int64_t& bucketNum) { + VLOG("advanceMostRecentBucketTo() called."); + if (bucketNum <= mMostRecentBucketNum) { + ALOGW("Cannot advance buckets backwards (bucketNum=%lld but mMostRecentBucketNum=%lld)", + (long long)bucketNum, (long long)mMostRecentBucketNum); return; } - - // The past packets are ancient. Empty out old mPastBuckets[i] values and reset - // mSumOverPastBuckets. - if (latestPastBucketNum - mMostRecentBucketNum >= mNumOfPastBuckets) { + // If in the future (i.e. buckets are ancient), just empty out all past info. + if (bucketNum >= mMostRecentBucketNum + mNumOfPastBuckets) { resetStorage(); - } else { - for (int64_t i = std::max(0LL, (long long)(mMostRecentBucketNum - mNumOfPastBuckets + 1)); - i <= latestPastBucketNum - mNumOfPastBuckets; i++) { - const int idx = index(i); - subtractBucketFromSum(mPastBuckets[idx]); - mPastBuckets[idx] = nullptr; // release (but not clear) the old bucket. - } + mMostRecentBucketNum = bucketNum; + return; } - // It is an update operation. - if (latestPastBucketNum <= mMostRecentBucketNum && - latestPastBucketNum > mMostRecentBucketNum - mNumOfPastBuckets) { - subtractBucketFromSum(mPastBuckets[index(latestPastBucketNum)]); + // Clear out space by emptying out old mPastBuckets[i] values and update mSumOverPastBuckets. + for (int64_t i = mMostRecentBucketNum + 1; i <= bucketNum; i++) { + const int idx = index(i); + subtractBucketFromSum(mPastBuckets[idx]); + mPastBuckets[idx] = nullptr; // release (but not clear) the old bucket. } + mMostRecentBucketNum = bucketNum; } -void AnomalyTracker::addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue, +void AnomalyTracker::addPastBucket(const MetricDimensionKey& key, + const int64_t& bucketValue, const int64_t& bucketNum) { - if (mNumOfPastBuckets == 0) { + VLOG("addPastBucket(bucketValue) called."); + if (mNumOfPastBuckets == 0 || + bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) { return; } - flushPastBuckets(bucketNum); - auto& bucket = mPastBuckets[index(bucketNum)]; - if (bucket == nullptr) { - bucket = std::make_shared(); + const int bucketIndex = index(bucketNum); + if (bucketNum <= mMostRecentBucketNum && (mPastBuckets[bucketIndex] != nullptr)) { + // We need to insert into an already existing past bucket. + std::shared_ptr& bucket = mPastBuckets[bucketIndex]; + auto itr = bucket->find(key); + if (itr != bucket->end()) { + // Old entry already exists; update it. + subtractValueFromSum(key, itr->second); + itr->second = bucketValue; + } else { + bucket->insert({key, bucketValue}); + } + mSumOverPastBuckets[key] += bucketValue; + } else { + // Bucket does not exist yet (in future or was never made), so we must make it. + std::shared_ptr bucket = std::make_shared(); + bucket->insert({key, bucketValue}); + addPastBucket(bucket, bucketNum); } - bucket->insert({key, bucketValue}); - addBucketToSum(bucket); - mMostRecentBucketNum = std::max(mMostRecentBucketNum, bucketNum); } -void AnomalyTracker::addPastBucket(std::shared_ptr bucketValues, +void AnomalyTracker::addPastBucket(std::shared_ptr bucket, const int64_t& bucketNum) { - VLOG("addPastBucket() called."); - if (mNumOfPastBuckets == 0) { + VLOG("addPastBucket(bucket) called."); + if (mNumOfPastBuckets == 0 || + bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) { return; } - flushPastBuckets(bucketNum); - // Replace the oldest bucket with the new bucket we are adding. - mPastBuckets[index(bucketNum)] = bucketValues; - addBucketToSum(bucketValues); - mMostRecentBucketNum = std::max(mMostRecentBucketNum, bucketNum); + + if (bucketNum <= mMostRecentBucketNum) { + // We are updating an old bucket, not adding a new one. + subtractBucketFromSum(mPastBuckets[index(bucketNum)]); + } else { + // Clear space for the new bucket to be at bucketNum. + advanceMostRecentBucketTo(bucketNum); + } + mPastBuckets[index(bucketNum)] = bucket; + addBucketToSum(bucket); } void AnomalyTracker::subtractBucketFromSum(const shared_ptr& bucket) { if (bucket == nullptr) { return; } - // For each dimension present in the bucket, subtract its value from its corresponding sum. for (const auto& keyValuePair : *bucket) { - auto itr = mSumOverPastBuckets.find(keyValuePair.first); - if (itr == mSumOverPastBuckets.end()) { - continue; - } - itr->second -= keyValuePair.second; - // TODO: No need to look up the object twice like this. Use a var. - if (itr->second == 0) { - mSumOverPastBuckets.erase(itr); - } + subtractValueFromSum(keyValuePair.first, keyValuePair.second); + } +} + + +void AnomalyTracker::subtractValueFromSum(const MetricDimensionKey& key, + const int64_t& bucketValue) { + auto itr = mSumOverPastBuckets.find(key); + if (itr == mSumOverPastBuckets.end()) { + return; + } + itr->second -= bucketValue; + if (itr->second == 0) { + mSumOverPastBuckets.erase(itr); } } @@ -154,7 +170,8 @@ void AnomalyTracker::addBucketToSum(const shared_ptr& bucket) { int64_t AnomalyTracker::getPastBucketValue(const MetricDimensionKey& key, const int64_t& bucketNum) const { - if (mNumOfPastBuckets == 0 || bucketNum < 0) { + if (bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets + || bucketNum > mMostRecentBucketNum) { return 0; } @@ -174,11 +191,13 @@ int64_t AnomalyTracker::getSumOverPastBuckets(const MetricDimensionKey& key) con return 0; } -bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const MetricDimensionKey& key, +bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, + const MetricDimensionKey& key, const int64_t& currentBucketValue) { + + // currentBucketNum should be the next bucket after pastBuckets. If not, advance so that it is. if (currentBucketNum > mMostRecentBucketNum + 1) { - // TODO: This creates a needless 0 entry in mSumOverPastBuckets. Fix this. - addPastBucket(key, 0, currentBucketNum - 1); + advanceMostRecentBucketTo(currentBucketNum - 1); } return mAlert.has_trigger_if_sum_gt() && getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt(); @@ -190,19 +209,17 @@ void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const MetricDim VLOG("Skipping anomaly declaration since within refractory period"); return; } - mRefractoryPeriodEndsSec[key] = (timestampNs / NS_PER_SEC) + mAlert.refractory_period_secs(); - - // TODO: If we had access to the bucket_size_millis, consider calling resetStorage() - // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) { resetStorage(); } + if (mAlert.has_refractory_period_secs()) { + mRefractoryPeriodEndsSec[key] = ((timestampNs + NS_PER_SEC - 1) / NS_PER_SEC) // round up + + mAlert.refractory_period_secs(); + // TODO: If we had access to the bucket_size_millis, consider calling resetStorage() + // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) {resetStorage();} + } if (!mSubscriptions.empty()) { - if (mAlert.has_id()) { - ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.", mAlert.id(), - key.toString().c_str()); - informSubscribers(key); - } else { - ALOGI("An anomaly (with no id) has occurred! Not informing any subscribers."); - } + ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.", + mAlert.id(), key.toString().c_str()); + informSubscribers(key); } else { ALOGI("An anomaly has occurred! (But no subscriber for that alert.)"); } @@ -227,7 +244,7 @@ bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs, const MetricDimensionKey& key) { const auto& it = mRefractoryPeriodEndsSec.find(key); if (it != mRefractoryPeriodEndsSec.end()) { - if ((timestampNs / NS_PER_SEC) <= it->second) { + if (timestampNs < it->second * NS_PER_SEC) { return true; } else { mRefractoryPeriodEndsSec.erase(key); diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h index d27dee843b22a0ebb6808b7976f7fe0dd0aad7cd..d3da7dcf241b9c22a12bac9b0c7eb71bd8a72991 100644 --- a/cmds/statsd/src/anomaly/AnomalyTracker.h +++ b/cmds/statsd/src/anomaly/AnomalyTracker.h @@ -47,20 +47,32 @@ public: mSubscriptions.push_back(subscription); } - // Adds a bucket. - // Bucket index starts from 0. - void addPastBucket(std::shared_ptr bucketValues, const int64_t& bucketNum); + // Adds a bucket for the given bucketNum (index starting at 0). + // If a bucket for bucketNum already exists, it will be replaced. + // Also, advances to bucketNum (if not in the past), effectively filling any intervening + // buckets with 0s. + void addPastBucket(std::shared_ptr bucket, const int64_t& bucketNum); + + // Inserts (or replaces) the bucket entry for the given bucketNum at the given key to be the + // given bucketValue. If the bucket does not exist, it will be created. + // Also, advances to bucketNum (if not in the past), effectively filling any intervening + // buckets with 0s. void addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue, const int64_t& bucketNum); - // Returns true if detected anomaly for the existing buckets on one or more dimension keys. + // Returns true if, based on past buckets plus the new currentBucketValue (which generally + // represents the partially-filled current bucket), an anomaly has happened. + // Also advances to currBucketNum-1. bool detectAnomaly(const int64_t& currBucketNum, const MetricDimensionKey& key, const int64_t& currentBucketValue); // Informs incidentd about the detected alert. void declareAnomaly(const uint64_t& timestampNs, const MetricDimensionKey& key); - // Detects the alert and informs the incidentd when applicable. + // Detects if, based on past buckets plus the new currentBucketValue (which generally + // represents the partially-filled current bucket), an anomaly has happened, and if so, + // declares an anomaly and informs relevant subscribers. + // Also advances to currBucketNum-1. void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum, const MetricDimensionKey& key, const int64_t& currentBucketValue); @@ -69,24 +81,26 @@ public: return; // Base AnomalyTracker class has no need for the AlarmMonitor. } - // Helper function to return the sum value of past buckets at given dimension. + // Returns the sum of all past bucket values for the given dimension key. int64_t getSumOverPastBuckets(const MetricDimensionKey& key) const; - // Helper function to return the value for a past bucket. + // Returns the value for a past bucket, or 0 if that bucket doesn't exist. int64_t getPastBucketValue(const MetricDimensionKey& key, const int64_t& bucketNum) const; - // Returns the anomaly threshold. + // Returns the anomaly threshold set in the configuration. inline int64_t getAnomalyThreshold() const { return mAlert.trigger_if_sum_gt(); } - // Returns the refractory period timestamp (in seconds) for the given key. + // Returns the refractory period ending timestamp (in seconds) for the given key. + // Before this moment, any detected anomaly will be ignored. // If there is no stored refractory period ending timestamp, returns 0. uint32_t getRefractoryPeriodEndsSec(const MetricDimensionKey& key) const { const auto& it = mRefractoryPeriodEndsSec.find(key); return it != mRefractoryPeriodEndsSec.end() ? it->second : 0; } + // Returns the (constant) number of past buckets this anomaly tracker can store. inline int getNumOfPastBuckets() const { return mNumOfPastBuckets; } @@ -112,22 +126,27 @@ protected: // for the anomaly detection (since the current bucket is not in the past). const int mNumOfPastBuckets; - // The existing bucket list. + // Values for each of the past mNumOfPastBuckets buckets. Always of size mNumOfPastBuckets. + // mPastBuckets[i] can be null, meaning that no data is present in that bucket. std::vector> mPastBuckets; - // Sum over all existing buckets cached in mPastBuckets. + // Cached sum over all existing buckets in mPastBuckets. + // Its buckets never contain entries of 0. DimToValMap mSumOverPastBuckets; // The bucket number of the last added bucket. int64_t mMostRecentBucketNum = -1; // Map from each dimension to the timestamp that its refractory period (if this anomaly was - // declared for that dimension) ends, in seconds. Only anomalies that occur after this period - // ends will be declared. + // declared for that dimension) ends, in seconds. From this moment and onwards, anomalies + // can be declared again. // Entries may be, but are not guaranteed to be, removed after the period is finished. unordered_map mRefractoryPeriodEndsSec; - void flushPastBuckets(const int64_t& currBucketNum); + // Advances mMostRecentBucketNum to bucketNum, deleting any data that is now too old. + // Specifically, since it is now too old, removes the data for + // [mMostRecentBucketNum - mNumOfPastBuckets + 1, bucketNum - mNumOfPastBuckets]. + void advanceMostRecentBucketTo(const int64_t& bucketNum); // Add the information in the given bucket to mSumOverPastBuckets. void addBucketToSum(const shared_ptr& bucket); @@ -136,15 +155,21 @@ protected: // and remove any items with value 0. void subtractBucketFromSum(const shared_ptr& bucket); + // From mSumOverPastBuckets[key], subtracts bucketValue, removing it if it is now 0. + void subtractValueFromSum(const MetricDimensionKey& key, const int64_t& bucketValue); + + // Returns true if in the refractory period, else false. + // If there is a stored refractory period but it ended prior to timestampNs, it is removed. bool isInRefractoryPeriod(const uint64_t& timestampNs, const MetricDimensionKey& key); // Calculates the corresponding bucket index within the circular array. + // Requires bucketNum >= 0. size_t index(int64_t bucketNum) const; // Resets all bucket data. For use when all the data gets stale. virtual void resetStorage(); - // Informs the subscribers that an anomaly has occurred. + // Informs the subscribers (incidentd, perfetto, broadcasts, etc) that an anomaly has occurred. void informSubscribers(const MetricDimensionKey& key); FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets); diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp index 31d50be7ec262818541a13c908d8d047b93354a3..d85157c8159a309d1cbb7e7c7b1469a1b5386f7e 100644 --- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp +++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp @@ -26,30 +26,13 @@ namespace statsd { DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey, const sp& alarmMonitor) - : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) { + : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) { + VLOG("DurationAnomalyTracker() called"); } DurationAnomalyTracker::~DurationAnomalyTracker() { - stopAllAlarms(); -} - -void DurationAnomalyTracker::resetStorage() { - AnomalyTracker::resetStorage(); - if (!mAlarms.empty()) VLOG("AnomalyTracker.resetStorage() called but mAlarms is NOT empty!"); -} - -void DurationAnomalyTracker::declareAnomalyIfAlarmExpired(const MetricDimensionKey& dimensionKey, - const uint64_t& timestampNs) { - auto itr = mAlarms.find(dimensionKey); - if (itr == mAlarms.end()) { - return; - } - - if (itr->second != nullptr && - static_cast(timestampNs / NS_PER_SEC) >= itr->second->timestampSec) { - declareAnomaly(timestampNs, dimensionKey); - stopAlarm(dimensionKey); - } + VLOG("~DurationAnomalyTracker() called"); + cancelAllAlarms(); } void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey, @@ -57,34 +40,47 @@ void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey, // Alarms are stored in secs. Must round up, since if it fires early, it is ignored completely. uint32_t timestampSec = static_cast((timestampNs -1)/ NS_PER_SEC) + 1; // round up if (isInRefractoryPeriod(timestampNs, dimensionKey)) { + // TODO: Bug! By the refractory's end, the data might be erased and the alarm inapplicable. VLOG("Setting a delayed anomaly alarm lest it fall in the refractory period"); timestampSec = getRefractoryPeriodEndsSec(dimensionKey) + 1; } + + auto itr = mAlarms.find(dimensionKey); + if (itr != mAlarms.end() && mAlarmMonitor != nullptr) { + mAlarmMonitor->remove(itr->second); + } + sp alarm = new InternalAlarm{timestampSec}; - mAlarms.insert({dimensionKey, alarm}); + mAlarms[dimensionKey] = alarm; if (mAlarmMonitor != nullptr) { mAlarmMonitor->add(alarm); } } -void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey) { - auto itr = mAlarms.find(dimensionKey); - if (itr != mAlarms.end()) { - mAlarms.erase(dimensionKey); - if (mAlarmMonitor != nullptr) { - mAlarmMonitor->remove(itr->second); - } +void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey, + const uint64_t& timestampNs) { + const auto itr = mAlarms.find(dimensionKey); + if (itr == mAlarms.end()) { + return; } -} -void DurationAnomalyTracker::stopAllAlarms() { - std::set keys; - for (auto itr = mAlarms.begin(); itr != mAlarms.end(); ++itr) { - keys.insert(itr->first); + // If the alarm is set in the past but hasn't fired yet (due to lag), catch it now. + if (itr->second != nullptr && timestampNs >= NS_PER_SEC * itr->second->timestampSec) { + declareAnomaly(timestampNs, dimensionKey); } - for (auto key : keys) { - stopAlarm(key); + mAlarms.erase(dimensionKey); + if (mAlarmMonitor != nullptr) { + mAlarmMonitor->remove(itr->second); + } +} + +void DurationAnomalyTracker::cancelAllAlarms() { + if (mAlarmMonitor != nullptr) { + for (const auto& itr : mAlarms) { + mAlarmMonitor->remove(itr.second); + } } + mAlarms.clear(); } void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs, diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h index 51186df3e93d9749c1b163c8bca48a5ed1f5d300..92bb2bc1515b1826efe2b133a40910f63ed2e161 100644 --- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h +++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h @@ -32,21 +32,20 @@ public: virtual ~DurationAnomalyTracker(); - // Starts the alarm at the given timestamp. + // Sets an alarm for the given timestamp. + // Replaces previous alarm if one already exists. void startAlarm(const MetricDimensionKey& dimensionKey, const uint64_t& eventTime); // Stops the alarm. - void stopAlarm(const MetricDimensionKey& dimensionKey); + // If it should have already fired, but hasn't yet (e.g. because the AlarmManager is delayed), + // declare the anomaly now. + void stopAlarm(const MetricDimensionKey& dimensionKey, const uint64_t& timestampNs); - // Stop all the alarms owned by this tracker. - void stopAllAlarms(); - - // Declares the anomaly when the alarm expired given the current timestamp. - void declareAnomalyIfAlarmExpired(const MetricDimensionKey& dimensionKey, - const uint64_t& timestampNs); + // Stop all the alarms owned by this tracker. Does not declare any anomalies. + void cancelAllAlarms(); // Declares an anomaly for each alarm in firedAlarms that belongs to this DurationAnomalyTracker - // and removes it from firedAlarms. + // and removes it from firedAlarms. The AlarmMonitor is not informed. // Note that this will generally be called from a different thread from the other functions; // the caller is responsible for thread safety. void informAlarmsFired(const uint64_t& timestampNs, @@ -60,9 +59,6 @@ protected: // Anomaly alarm monitor. sp mAlarmMonitor; - // Resets all bucket data. For use when all the data gets stale. - void resetStorage() override; - FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp); FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm); FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm); diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto index 19d00b7dc4a5bbec6598150d54c2a85e339f83de..a2a03b14c073c1fdd5530d6fcf11fbd5092581ee 100644 --- a/cmds/statsd/src/atom_field_options.proto +++ b/cmds/statsd/src/atom_field_options.proto @@ -67,4 +67,7 @@ message StateAtomFieldOption { extend google.protobuf.FieldOptions { // Flags to decorate an atom that presents a state change. optional StateAtomFieldOption stateFieldOption = 50000; + + // Flags to decorate the uid fields in an atom. + optional bool is_uid = 50001 [default = false]; } \ No newline at end of file diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 9bfbd38f89323a5ddc76c69ca6d7d47e097efef0..40eff4c2bd03d7526d624177c0b61006bfcefd29 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -23,6 +23,7 @@ option java_outer_classname = "AtomsProto"; import "frameworks/base/cmds/statsd/src/atom_field_options.proto"; import "frameworks/base/core/proto/android/app/enums.proto"; +import "frameworks/base/core/proto/android/bluetooth/enums.proto"; import "frameworks/base/core/proto/android/os/enums.proto"; import "frameworks/base/core/proto/android/server/enums.proto"; import "frameworks/base/core/proto/android/telecomm/enums.proto"; @@ -106,7 +107,16 @@ message Atom { KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64; AppDied app_died=65; ResourceConfigurationChanged resource_configuration_changed = 66; - // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15. + 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; + MobileConnectionStateChanged mobile_connection_state_changed = 75; + MobileRadioTechnologyChanged mobile_radio_technology_changed = 76; } // Pulled events will start at field 10000. @@ -199,7 +209,7 @@ message ScreenStateChanged { * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java */ message UidProcessStateChanged { - optional int32 uid = 1 [(stateFieldOption).option = PRIMARY]; + optional int32 uid = 1 [(stateFieldOption).option = PRIMARY, (is_uid) = true]; // The state, from frameworks/base/core/proto/android/app/enums.proto. optional android.app.ProcessStateEnum state = 2 [(stateFieldOption).option = EXCLUSIVE]; @@ -213,7 +223,7 @@ message UidProcessStateChanged { */ message ProcessLifeCycleStateChanged { // TODO: should be a string tagged w/ uid annotation - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // The process name (usually same as the app name). optional string name = 2; @@ -583,7 +593,7 @@ message WakeupAlarmOccurred { */ message MobileRadioPowerStateChanged { // TODO: Add attribution instead of uid? - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // Power state, from frameworks/base/core/proto/android/telephony/enums.proto. optional android.telephony.DataConnectionPowerStateEnum state = 2; @@ -598,7 +608,7 @@ message MobileRadioPowerStateChanged { */ message WifiRadioPowerStateChanged { // TODO: Add attribution instead of uid? - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // Power state, from frameworks/base/core/proto/android/telephony/enums.proto. optional android.telephony.DataConnectionPowerStateEnum state = 2; @@ -903,6 +913,215 @@ message ResourceConfigurationChanged { optional int32 uiMode = 17; } + +/** + * Logs changes in the connection state of the mobile radio. + * + * Logged from: + * frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/DataConnection.java + */ +message MobileConnectionStateChanged { + // States are from the state machine DataConnection.java. + enum State { + UNKNOWN = 0; + // The connection is inactive, or disconnected. + INACTIVE = 1; + // The connection is being activated, or connecting. + ACTIVATING = 2; + // The connection is active, or connected. + ACTIVE = 3; + // The connection is disconnecting. + DISCONNECTING = 4; + // The connection is disconnecting after creating a connection. + DISCONNECTION_ERROR_CREATING_CONNECTION = 5; + } + optional State state = 1; + // For multi-sim phones, this distinguishes between the sim cards. + optional int32 sim_slot_index = 2; + // Used to identify the connection. Starts at 0 and increments by 1 for + // every new network created. Resets whenever the device reboots. + optional int32 data_connection_id = 3; + // A bitmask for the capabilities of this connection. + // Eg. DEFAULT (internet), MMS, SUPL, DUN, IMS. + // Default value (if we have no information): 0 + optional int64 capabilities = 4; + // If this connection has internet. + // This just checks if the DEFAULT bit of capabilities is set. + optional bool has_internet = 5; +} + +/** + * Logs changes in mobile radio technology. eg: LTE, EDGE, CDMA. + * + * Logged from: + * frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java + */ +message MobileRadioTechnologyChanged { + optional android.telephony.NetworkTypeEnum state = 1; + // For multi-sim phones, this distinguishes between the sim cards. + optional int32 sim_slot_index = 2; +} + + +/** + * Logs when Bluetooth is enabled and disabled. + * + * Logged from: + * services/core/java/com/android/server/BluetoothManagerService.java + */ +message BluetoothEnabledStateChanged { + repeated AttributionNode attribution_node = 1; + // Whether or not bluetooth is enabled on the device. + enum State { + UNKNOWN = 0; + ENABLED = 1; + DISABLED = 2; + } + optional State state = 2; + // The reason for being enabled/disabled. + // Eg. Airplane mode, crash, application request. + optional android.bluetooth.EnableDisableReasonEnum reason = 3; + // If the reason is an application request, this will be the package name. + optional string pkgName = 4; +} + +/** + * Logs when a Bluetooth device connects and disconnects. + * + * Logged from: + * packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java + */ +message BluetoothConnectionStateChanged { + // The state of the connection. + // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED. + optional android.bluetooth.ConnectionStateEnum state = 1; + // An identifier that can be used to match connect and disconnect events. + // Currently is last two bytes of a hash of a device level ID and + // the mac address of the bluetooth device that is connected. + optional int32 obfuscated_id = 2; + // The profile that is connected. Eg. GATT, A2DP, HEADSET. + // From android.bluetooth.BluetoothAdapter.java + optional int32 bt_profile = 3; +} + +/** + * Logs when Bluetooth A2dp audio streaming state changes. + * + * Logged from: + * TODO(b/73971848) + */ +message BluetoothA2dpAudioStateChanged { + // Whether or not audio is being played using Bluetooth A2dp. + enum State { + UNKNOWN = 0; + PLAY = 1; + STOP = 2; + } + optional State state = 1; +} + +/** + * 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 * @@ -911,7 +1130,8 @@ message ResourceConfigurationChanged { */ message DaveyOccurred { // The UID that logged this atom. - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; + ; // Amount of time it took to render the frame. Should be >=700ms. optional int64 jank_duration_millis = 2; @@ -931,7 +1151,7 @@ message PhoneSignalStrengthChanged { /** * Logs that a setting was updated. * Logged from: - * frameworks/base/core/java/android/provider/Settings.java + * frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java * The tag and is_default allow resetting of settings to default values based on the specified * tag. See Settings#putString(ContentResolver, String, String, String, boolean) for more details. */ @@ -957,8 +1177,14 @@ message SettingChanged { // True if this setting with tag should be resettable. optional bool is_default = 6; - // The user ID associated. Defined in android/os/UserHandle.java + // The associated user (for multi-user feature). Defined in android/os/UserHandle.java optional int32 user = 7; + + enum ChangeReason { + UPDATED = 1; // Updated can be an insertion or an update. + DELETED = 2; + } + optional ChangeReason reason = 8; } /** @@ -968,7 +1194,7 @@ message SettingChanged { * frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java */ message ActivityForegroundStateChanged { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; optional string pkg_name = 2; optional string class_name = 3; @@ -986,7 +1212,7 @@ message ActivityForegroundStateChanged { */ message DropboxErrorChanged { // The uid if available. -1 means not available. - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // Tag used when recording this error to dropbox. Contains data_ or system_ prefix. optional string tag = 2; @@ -1017,7 +1243,7 @@ message DropboxErrorChanged { */ message AppBreadcrumbReported { // The uid of the application that sent this custom atom. - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // An arbitrary label chosen by the developer. For Android P, the label should be in [0, 16). optional int32 label = 2; @@ -1041,7 +1267,7 @@ message AppBreadcrumbReported { */ message AnomalyDetected { // Uid that owns the config whose anomaly detection alert fired. - optional int32 config_uid = 1; + optional int32 config_uid = 1 [(is_uid) = true]; // Id of the config whose anomaly detection alert fired. optional int64 config_id = 2; @@ -1052,7 +1278,7 @@ message AnomalyDetected { message AppStartChanged { // The uid if available. -1 means not available. - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // The app package name. optional string pkg_name = 2; @@ -1099,7 +1325,7 @@ message AppStartChanged { message AppStartCancelChanged { // The uid if available. -1 means not available. - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // The app package name. optional string pkg_name = 2; @@ -1119,7 +1345,7 @@ message AppStartCancelChanged { message AppStartFullyDrawnChanged { // The uid if available. -1 means not available. - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // The app package name. optional string pkg_name = 2; @@ -1150,7 +1376,7 @@ message AppStartFullyDrawnChanged { */ message PictureInPictureStateChanged { // -1 if it is not available - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; optional string short_name = 2; @@ -1169,7 +1395,7 @@ message PictureInPictureStateChanged { * services/core/java/com/android/server/wm/Session.java */ message OverlayStateChanged { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; optional string package_name = 2; @@ -1190,7 +1416,7 @@ message OverlayStateChanged { * //frameworks/base/services/core/java/com/android/server/am/ActiveServices.java */ message ForegroundServiceStateChanged { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // package_name + "/" + class_name optional string short_name = 2; @@ -1210,6 +1436,7 @@ message ForegroundServiceStateChanged { * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java */ message IsolatedUidChanged { + // NOTE: DO NOT annotate uid field in this atom. This atom is specially handled in statsd. // The host UID. Generally, we should attribute metrics from the isolated uid to the host uid. optional int32 parent_uid = 1; @@ -1231,7 +1458,7 @@ message IsolatedUidChanged { message PacketWakeupOccurred { // The uid owning the socket into which the packet was delivered, or -1 if the packet was // delivered nowhere. - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // The interface name on which the packet was received. optional string iface = 2; // The ethertype value of the packet. @@ -1259,7 +1486,7 @@ message PacketWakeupOccurred { */ message AppStartMemoryStateCaptured { // The uid if available. -1 means not available. - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // The process name. optional string process_name = 2; @@ -1305,7 +1532,7 @@ message LmkStateChanged { */ message LmkKillOccurred { // The uid if available. -1 means not available. - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // The process name. optional string process_name = 2; @@ -1337,7 +1564,7 @@ message LmkKillOccurred { */ message AppDied { // timestamp(elapsedRealtime) of record creation - optional uint64 timestamp_millis = 1; + optional uint64 timestamp_millis = 1 [(stateFieldOption).option = EXCLUSIVE]; } ////////////////////////////////////////////////////////////////////// @@ -1351,7 +1578,7 @@ message AppDied { * StatsCompanionService (using BatteryStats to get which interfaces are wifi) */ message WifiBytesTransfer { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; optional int64 rx_bytes = 2; @@ -1369,9 +1596,10 @@ message WifiBytesTransfer { * StatsCompanionService (using BatteryStats to get which interfaces are wifi) */ message WifiBytesTransferByFgBg { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; - // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats. + // 1 denotes foreground and 0 denotes background. This is called Set in + // NetworkStats. optional int32 is_foreground = 2; optional int64 rx_bytes = 3; @@ -1390,7 +1618,7 @@ message WifiBytesTransferByFgBg { * StatsCompanionService (using BatteryStats to get which interfaces are mobile data) */ message MobileBytesTransfer { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; optional int64 rx_bytes = 2; @@ -1408,9 +1636,10 @@ message MobileBytesTransfer { * StatsCompanionService (using BatteryStats to get which interfaces are mobile data) */ message MobileBytesTransferByFgBg { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; - // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats. + // 1 denotes foreground and 0 denotes background. This is called Set in + // NetworkStats. optional int32 is_foreground = 2; optional int64 rx_bytes = 3; @@ -1429,7 +1658,7 @@ message MobileBytesTransferByFgBg { * StatsCompanionService */ message BluetoothBytesTransfer { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; optional int64 rx_bytes = 2; @@ -1489,7 +1718,7 @@ message CpuTimePerFreq { * Note that isolated process uid time should be attributed to host uids. */ message CpuTimePerUid { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; optional uint64 user_time_millis = 2; optional uint64 sys_time_millis = 3; } @@ -1500,7 +1729,7 @@ message CpuTimePerUid { * For each uid, we order the time by descending frequencies. */ message CpuTimePerUidFreq { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; optional uint32 freq_index = 2; optional uint64 time_millis = 3; } @@ -1582,7 +1811,7 @@ message BluetoothActivityInfo { */ message ProcessMemoryState { // The uid if available. -1 means not available. - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; // The process name. optional string process_name = 2; @@ -1634,7 +1863,7 @@ message SystemUptime { * The file contains a monotonically increasing count of time for a single boot. */ message CpuActiveTime { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; optional uint64 time_millis = 2; } @@ -1648,7 +1877,7 @@ message CpuActiveTime { * The file contains a monotonically increasing count of time for a single boot. */ message CpuClusterTime { - optional int32 uid = 1; + optional int32 uid = 1 [(is_uid) = true]; optional int32 cluster_index = 2; optional uint64 time_millis = 3; } diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp index 4913aef3347ff4e5dda0fe0b43cfe5ee98791f56..73efb39ac1195e88062493d9715ad749c9faf0af 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 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 c68875c58162219f3aca51cf5f05edc8a217fdf2..fe1740b24dd43041c33ede7bd60f5c037538031d 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 keys; - vector 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 d0f55abe7033476fe09633d3405cab14f6ac5bc8..f5310a419c928771d89b4a25958dd8bf8606da43 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 lock(mMutex); + auto it = mConfigs.find(key); + + const int numBytes = config.ByteSize(); + vector 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 listener : mListeners) { broadcastList.push_back(listener); } @@ -137,7 +150,6 @@ void ConfigManager::RemoveConfigs(int uid) { { lock_guard 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& 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 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 a0c1c1cb16f8c1e8da16793eff00c0c4f093c558..9a38188a120c34a92b902cde000d987bd7e9300f 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& 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 mConfigs; diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp index 9513cc521af71239a04ca6ecebfa3c47eb3190f2..3b0cd349168dc6e14bb29a6972707c51e1e99102 100644 --- a/cmds/statsd/src/external/StatsPuller.cpp +++ b/cmds/statsd/src/external/StatsPuller.cpp @@ -21,6 +21,7 @@ #include "guardrail/StatsdStats.h" #include "puller_util.h" #include "stats_log_util.h" +#include "StatsPullerManagerImpl.h" namespace android { namespace os { @@ -34,11 +35,7 @@ void StatsPuller::SetUidMap(const sp& uidMap) { mUidMap = uidMap; } // ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently StatsPuller::StatsPuller(const int tagId) : mTagId(tagId) { - if (StatsdStats::kPullerCooldownMap.find(tagId) == StatsdStats::kPullerCooldownMap.end()) { - mCoolDownSec = StatsdStats::kDefaultPullerCooldown; - } else { - mCoolDownSec = StatsdStats::kPullerCooldownMap[tagId]; - } + mCoolDownSec = StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.coolDownSec; VLOG("Puller for tag %d created. Cooldown set to %ld", mTagId, mCoolDownSec); } diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp index 72a00cb6834e0e80a6e71086bb011759de83dbd0..fb0be733bc749abc501ae6b9082be8e293a2561c 100644 --- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp +++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp @@ -166,6 +166,11 @@ void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp re // Round it to the nearest minutes. This is the limit of alarm manager. // In practice, we should limit it higher. long roundedIntervalMs = intervalMs/1000/60 * 1000 * 60; + // Scheduled pulling should be at least 1 min apart. + // This can be lower in cts tests, in which case we round it to 1 min. + if (roundedIntervalMs < 60 * 1000) { + roundedIntervalMs = 60 * 1000; + } // There is only one alarm for all pulled events. So only set it to the smallest denom. if (roundedIntervalMs < mCurrentPullingInterval) { VLOG("Updating pulling interval %ld", intervalMs); diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp index 0b0c5c41bf9dceabd4797d6c1d658ffd01449cd1..ea23623d3b6cea22263c6a5ad9dc83547ec4599a 100644 --- a/cmds/statsd/src/external/puller_util.cpp +++ b/cmds/statsd/src/external/puller_util.cpp @@ -112,7 +112,8 @@ void mergeIsolatedUidsToHostUid(vector>& data, const sp #include "../stats_log_util.h" #include "statslog.h" +#include "storage/StorageManager.h" namespace android { namespace os { @@ -91,18 +92,6 @@ const int FIELD_ID_UID_MAP_BYTES_USED = 3; const int FIELD_ID_UID_MAP_DROPPED_SNAPSHOTS = 4; const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 5; -std::map StatsdStats::kPullerCooldownMap = { - {android::util::KERNEL_WAKELOCK, 1}, - {android::util::WIFI_BYTES_TRANSFER, 1}, - {android::util::MOBILE_BYTES_TRANSFER, 1}, - {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, 1}, - {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, 1}, - {android::util::SUBSYSTEM_SLEEP_STATE, 1}, - {android::util::CPU_TIME_PER_FREQ, 1}, - {android::util::CPU_TIME_PER_UID, 1}, - {android::util::CPU_TIME_PER_UID_FREQ, 1}, -}; - // TODO: add stats for pulled atoms. StatsdStats::StatsdStats() { mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1); @@ -415,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/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index c3f401324454c89c5afae6b54359cde0edf8058d..c42514a049258162c73723204398a86521d0d2d3 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -16,7 +16,6 @@ #pragma once #include "config/ConfigKey.h" -#include "frameworks/base/cmds/statsd/src/stats_log_common.pb.h" #include "statslog.h" #include @@ -111,13 +110,6 @@ public: /* Min period between two checks of byte size per config key in nanoseconds. */ static const unsigned long long kMinByteSizeCheckPeriodNs = 10 * NS_PER_SEC; - // Default minimum interval between pulls for an atom. Pullers can return cached values if - // another pull request happens within this interval. - static std::map kPullerCooldownMap; - - // Default cooldown time for a puller - static const long kDefaultPullerCooldown = 1; - // Maximum age (30 days) that files on disk can exist in seconds. static const int kMaxAgeSecond = 60 * 60 * 24 * 30; diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp index 364d4e9d5c9443c88fe021da337350c3ff3e6e4e..b7105b351a1056c75cf4a0ad22e7446a41e0283c 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/matchers/matcher_util.h b/cmds/statsd/src/matchers/matcher_util.h index ae946d16b352e26acd6aa9fc2e8aba52f218abfa..15b4a9799a930e61b470866c1140ff1819410fb4 100644 --- a/cmds/statsd/src/matchers/matcher_util.h +++ b/cmds/statsd/src/matchers/matcher_util.h @@ -24,7 +24,6 @@ #include #include #include -#include "frameworks/base/cmds/statsd/src/stats_log_common.pb.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "packages/UidMap.h" #include "stats_util.h" diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp index 22b2a30af328acb478226917e020b55c0d5750e0..8e8a529bfff177058035e64bc467813b68aed2e4 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 1d8e42be635cb1993862d3a8ce76cc85f3a62d3e..ef738acd5772c8dd64f2d35a366a28ca80e38252 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 bc09683d79ade0466033a50e1d4b84d2cc8eab3b..c6b9405e424d3e81d52099baf191b07f8eb77fea 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 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 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 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 6746e116333f08c08f57460b71fc7bc57ca68e4b..985749df63ddf34a1cd8b6756cd93a3d3f0d5e0c 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/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp index 778eb8e18896591580c0458cca321499d6cc0c7c..bd8b293e1f2a0b2581e0d488be287c2781746e0c 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.cpp +++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp @@ -134,8 +134,8 @@ void EventMetricProducer::onMatchedLogEventInternalLocked( uint64_t wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA); const bool truncateTimestamp = - android::util::kNotTruncatingTimestampAtomWhiteList.find(event.GetTagId()) == - android::util::kNotTruncatingTimestampAtomWhiteList.end(); + android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.find(event.GetTagId()) == + android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.end(); if (truncateTimestamp) { mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS, (long long)truncateTimestampNsToFiveMinutes(event.GetElapsedTimestampNs())); diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index e479e5caec2f4b7e2e2ebb10985f516dc612e57b..49034ac25c648485a8985f3118d164dae02b9711 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,29 @@ 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::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.find( + mTagId) == + android::util::AtomsInfo::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 +420,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 ca8dc7582680ad9f54bb5b6eb929ea0a0557eb2f..dd6aff4130de9530f008daa1f340fcb6e6c301e4 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 mGaugeAtoms; - uint64_t mBucketNum; }; typedef std::unordered_map> @@ -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 6c90b031a9cce02fc245c75f6c336c1c1f548df0..f4495a19d700164e7afafdfe74224dde36223976 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 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 1ca59a366fcb17bdd63f43c8755cee8405f9ed98..c773d4f1387e4de60d4ecd8d3aed202de70e4811 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, const sp& anomalyAlarmMonitor, const sp& 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, @@ -62,15 +64,9 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, mTrackerToConditionMap, mNoReportMetricIds); if (config.allowed_log_source_size() == 0) { - // TODO(b/70794411): uncomment the following line and remove the hard coded log source - // after all configs have the log source added. - // mConfigValid = false; - // ALOGE("Log source white list is empty! This config won't get any data."); - - mAllowedUid.push_back(AID_ROOT); - mAllowedUid.push_back(AID_STATSD); - mAllowedUid.push_back(AID_SYSTEM); - mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end()); + mConfigValid = false; + ALOGE("Log source whitelist is empty! This config won't get any data. Suggest adding at " + "least AID_SYSTEM and AID_STATSD to the allowed_log_source field."); } else { for (const auto& source : config.allowed_log_source()) { auto it = UidMap::sAidToUidMapping.find(source); @@ -193,6 +189,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 dbab81431743b074096946914221666fe3bcd5e8..46a9b34c21a1329485d5cbc2e3e0daf636e01d2f 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 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 09913dc513fd140499b5709a2ba70af739e158b0..767260d263516f2103dea2110d3046097d27e4d6 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 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 5e42bd255df40e4a4738a4490ff33927f55152b0..be57183bd926b6b1c3153dca33879c598f9bcec1 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 7b3393fda7e6ef02e7bdf4377bc0fd89a4540114..991a76a0d34a54e8a238c8470549075be0e1579b 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 { @@ -129,11 +128,11 @@ protected: } } - // Stops the anomaly alarm. - void stopAnomalyAlarm() { + // Stops the anomaly alarm. If it should have already fired, declare the anomaly now. + void stopAnomalyAlarm(const uint64_t timestamp) { for (auto& anomalyTracker : mAnomalyTrackers) { if (anomalyTracker != nullptr) { - anomalyTracker->stopAlarm(mEventKey); + anomalyTracker->stopAlarm(mEventKey, timestamp); } } } @@ -156,14 +155,6 @@ protected: } } - void declareAnomalyIfAlarmExpired(const uint64_t& timestamp) { - for (auto& anomalyTracker : mAnomalyTrackers) { - if (anomalyTracker != nullptr) { - anomalyTracker->declareAnomalyIfAlarmExpired(mEventKey, timestamp); - } - } - } - // Convenience to compute the current bucket's end time, which is always aligned with the // start time of the metric. uint64_t getCurrentBucketEndTimeNs() { diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp index 8e0bf2678fea228e86b197ed9ca25cd5acb0c638..335ec4c7cbd59c91161b61719a06fe06e72bf7b0 100644 --- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp @@ -130,7 +130,7 @@ void MaxDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_ case DurationState::kStarted: { duration.startCount--; if (forceStop || !mNested || duration.startCount <= 0) { - stopAnomalyAlarm(); + stopAnomalyAlarm(eventTime); duration.state = DurationState::kStopped; int64_t durationTime = eventTime - duration.lastStartTime; VLOG("Max, key %s, Stop %lld %lld %lld", key.toString().c_str(), @@ -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); @@ -285,7 +284,7 @@ void MaxDurationTracker::noteConditionChanged(const HashableDimensionKey& key, b // If condition becomes false, kStarted -> kPaused. Record the current duration and // stop anomaly alarm. if (!conditionMet) { - stopAnomalyAlarm(); + stopAnomalyAlarm(timestamp); it->second.state = DurationState::kPaused; it->second.lastDuration += (timestamp - it->second.lastStartTime); if (anyStarted()) { diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp index 2358415dfaf718c60658fd5c3cb59d2f6bfed010..b418a85a045cda4875a2f149294a9c5558310bb5 100644 --- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp @@ -92,7 +92,6 @@ void OringDurationTracker::noteStart(const HashableDimensionKey& key, bool condi void OringDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t timestamp, const bool stopAll) { - declareAnomalyIfAlarmExpired(timestamp); VLOG("Oring: %s stop", key.toString().c_str()); auto it = mStarted.find(key); if (it != mStarted.end()) { @@ -118,12 +117,11 @@ void OringDurationTracker::noteStop(const HashableDimensionKey& key, const uint6 } } if (mStarted.empty()) { - stopAnomalyAlarm(); + stopAnomalyAlarm(timestamp); } } void OringDurationTracker::noteStopAll(const uint64_t timestamp) { - declareAnomalyIfAlarmExpired(timestamp); if (!mStarted.empty()) { mDuration += (timestamp - mLastStartTime); VLOG("Oring Stop all: record duration %lld %lld ", (long long)timestamp - mLastStartTime, @@ -131,7 +129,7 @@ void OringDurationTracker::noteStopAll(const uint64_t timestamp) { detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration + mDurationFullBucket); } - stopAnomalyAlarm(); + stopAnomalyAlarm(timestamp); mStarted.clear(); mPaused.clear(); mConditionKeyMap.clear(); @@ -165,13 +163,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 +179,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); } } @@ -215,7 +211,6 @@ bool OringDurationTracker::flushIfNeeded( } void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) { - declareAnomalyIfAlarmExpired(timestamp); vector> startedToPaused; vector> pausedToStarted; if (!mStarted.empty()) { @@ -293,12 +288,11 @@ void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) mPaused.insert(startedToPaused.begin(), startedToPaused.end()); if (mStarted.empty()) { - stopAnomalyAlarm(); + stopAnomalyAlarm(timestamp); } } void OringDurationTracker::onConditionChanged(bool condition, const uint64_t timestamp) { - declareAnomalyIfAlarmExpired(timestamp); if (condition) { if (!mPaused.empty()) { VLOG("Condition true, all started"); @@ -321,7 +315,7 @@ void OringDurationTracker::onConditionChanged(bool condition, const uint64_t tim } } if (mStarted.empty()) { - stopAnomalyAlarm(); + stopAnomalyAlarm(timestamp); } } @@ -330,12 +324,16 @@ int64_t OringDurationTracker::predictAnomalyTimestampNs( // TODO: Unit-test this and see if it can be done more efficiently (e.g. use int32). // All variables below represent durations (not timestamps). + const int64_t thresholdNs = anomalyTracker.getAnomalyThreshold(); + // The time until the current bucket ends. This is how much more 'space' it can hold. const int64_t currRemainingBucketSizeNs = mBucketSizeNs - (eventTimestampNs - mCurrentBucketStartTimeNs); - // TODO: This should never be < 0. Document/guard against possible failures if it is. - - const int64_t thresholdNs = anomalyTracker.getAnomalyThreshold(); + if (currRemainingBucketSizeNs < 0) { + ALOGE("OringDurationTracker currRemainingBucketSizeNs < 0"); + // This should never happen. Return the safest thing possible given that data is corrupt. + return eventTimestampNs + thresholdNs; + } // As we move into the future, old buckets get overwritten (so their old data is erased). diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index b5afef2502f86cb5f06c972886339c556075abc9..c6112fdea7fac1a3a91817facca8f1d889a3f6e6 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -170,9 +170,10 @@ bool isStateTracker(const SimplePredicate& simplePredicate, vector* pri // 1. must not have "stop". must have "dimension" if (!simplePredicate.has_stop() && simplePredicate.has_dimensions()) { // TODO: need to check the start atom matcher too. - auto it = android::util::kStateAtomsFieldOptions.find(simplePredicate.dimensions().field()); + auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find( + simplePredicate.dimensions().field()); // 2. must be based on a state atom. - if (it != android::util::kStateAtomsFieldOptions.end()) { + if (it != android::util::AtomsInfo::kStateAtomsFieldOptions.end()) { // 3. dimension must be primary fields + state field IN ORDER size_t expectedDimensionCount = it->second.primaryFields.size() + 1; vector dimensions; @@ -562,6 +563,10 @@ bool initAlerts(const StatsdConfig& config, (long long)alert.metric_id()); return false; } + if (!alert.has_trigger_if_sum_gt()) { + ALOGW("invalid alert: missing threshold"); + return false; + } if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) { ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(), alert.num_buckets()); diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp index e322ca4bb1ac8f18d5ac4b7ef5dd9bd9e9dcabb9..3ba4b7a20fbedfec79001344edcdf0244c14ab5c 100644 --- a/cmds/statsd/src/packages/UidMap.cpp +++ b/cmds/statsd/src/packages/UidMap.cpp @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define DEBUG true // STOPSHIP if true +#define DEBUG false // STOPSHIP if true #include "Log.h" #include "stats_log_util.h" @@ -28,10 +28,33 @@ using namespace android; +using android::base::StringPrintf; +using android::util::FIELD_COUNT_REPEATED; +using android::util::FIELD_TYPE_BOOL; +using android::util::FIELD_TYPE_FLOAT; +using android::util::FIELD_TYPE_INT32; +using android::util::FIELD_TYPE_INT64; +using android::util::FIELD_TYPE_MESSAGE; +using android::util::FIELD_TYPE_STRING; +using android::util::ProtoOutputStream; + namespace android { namespace os { namespace statsd { +const int FIELD_ID_SNAPSHOT_PACKAGE_NAME = 1; +const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION = 2; +const int FIELD_ID_SNAPSHOT_PACKAGE_UID = 3; +const int FIELD_ID_SNAPSHOT_TIMESTAMP = 1; +const int FIELD_ID_SNAPSHOT_PACKAGE_INFO = 2; +const int FIELD_ID_SNAPSHOTS = 1; +const int FIELD_ID_CHANGES = 2; +const int FIELD_ID_CHANGE_DELETION = 1; +const int FIELD_ID_CHANGE_TIMESTAMP = 2; +const int FIELD_ID_CHANGE_PACKAGE = 3; +const int FIELD_ID_CHANGE_UID = 4; +const int FIELD_ID_CHANGE_VERSION = 5; + UidMap::UidMap() : mBytesUsed(0) {} UidMap::~UidMap() {} @@ -93,23 +116,35 @@ void UidMap::updateMap(const int64_t& timestamp, const vector& uid, lock_guard lock(mMutex); // Exclusively lock for updates. mMap.clear(); + ProtoOutputStream proto; + uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | + FIELD_ID_SNAPSHOT_PACKAGE_INFO); for (size_t j = 0; j < uid.size(); j++) { - mMap.insert(make_pair( - uid[j], AppData(string(String8(packageName[j]).string()), versionCode[j]))); + string package = string(String8(packageName[j]).string()); + mMap.insert(make_pair(uid[j], AppData(package, versionCode[j]))); + proto.write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, package); + proto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, (int)versionCode[j]); + proto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, (int)uid[j]); } - - auto snapshot = mOutput.add_snapshots(); - snapshot->set_elapsed_timestamp_nanos(timestamp); - for (size_t j = 0; j < uid.size(); j++) { - auto t = snapshot->add_package_info(); - t->set_name(string(String8(packageName[j]).string())); - t->set_version(int(versionCode[j])); - t->set_uid(uid[j]); + proto.end(token); + + // Copy ProtoOutputStream output to + auto iter = proto.data(); + size_t pos = 0; + vector outData(proto.size()); + while (iter.readBuffer() != NULL) { + size_t toRead = iter.currentToRead(); + std::memcpy(&(outData[pos]), iter.readBuffer(), toRead); + pos += toRead; + iter.rp()->move(toRead); } - mBytesUsed += snapshot->ByteSize(); + SnapshotRecord record(timestamp, outData); + mSnapshots.push_back(record); + + mBytesUsed += proto.size() + kBytesTimestampField; ensureBytesUsedBelowLimit(); StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); - StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size()); + StatsdStats::getInstance().setUidMapSnapshots(mSnapshots.size()); getListenerListCopyLocked(&broadcastList); } // To avoid invoking callback while holding the internal lock. we get a copy of the listener @@ -136,16 +171,11 @@ void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const i { lock_guard lock(mMutex); - auto log = mOutput.add_changes(); - log->set_deletion(false); - log->set_elapsed_timestamp_nanos(timestamp); - log->set_app(appName); - log->set_uid(uid); - log->set_version(versionCode); - mBytesUsed += log->ByteSize(); + mChanges.emplace_back(false, timestamp, appName, uid, versionCode); + mBytesUsed += kBytesChangeRecord; ensureBytesUsedBelowLimit(); StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); - StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size()); + StatsdStats::getInstance().setUidMapChanges(mChanges.size()); auto range = mMap.equal_range(int(uid)); bool found = false; @@ -180,17 +210,16 @@ void UidMap::ensureBytesUsedBelowLimit() { limit = maxBytesOverride; } while (mBytesUsed > limit) { - VLOG("Bytes used %zu is above limit %zu, need to delete something", mBytesUsed, limit); - if (mOutput.snapshots_size() > 0) { - auto snapshots = mOutput.mutable_snapshots(); - snapshots->erase(snapshots->begin()); // Remove first snapshot. + ALOGI("Bytes used %zu is above limit %zu, need to delete something", mBytesUsed, limit); + if (mSnapshots.size() > 0) { + mBytesUsed -= mSnapshots.front().bytes.size() + kBytesTimestampField; + mSnapshots.pop_front(); StatsdStats::getInstance().noteUidMapDropped(1, 0); - } else if (mOutput.changes_size() > 0) { - auto changes = mOutput.mutable_changes(); - changes->DeleteSubrange(0, 1); + } else if (mChanges.size() > 0) { + mBytesUsed -= kBytesChangeRecord; + mChanges.pop_front(); StatsdStats::getInstance().noteUidMapDropped(0, 1); } - mBytesUsed = mOutput.ByteSize(); } } @@ -217,15 +246,11 @@ void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const i { lock_guard lock(mMutex); - auto log = mOutput.add_changes(); - log->set_deletion(true); - log->set_elapsed_timestamp_nanos(timestamp); - log->set_app(app); - log->set_uid(uid); - mBytesUsed += log->ByteSize(); + mChanges.emplace_back(true, timestamp, app, uid, 0); + mBytesUsed += kBytesChangeRecord; ensureBytesUsedBelowLimit(); StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); - StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size()); + StatsdStats::getInstance().setUidMapChanges(mChanges.size()); auto range = mMap.equal_range(int(uid)); for (auto it = range.first; it != range.second; ++it) { @@ -281,7 +306,8 @@ int UidMap::getHostUidOrSelf(int uid) const { } void UidMap::clearOutput() { - mOutput.Clear(); + mSnapshots.clear(); + mChanges.clear(); // Also update the guardrail trackers. StatsdStats::getInstance().setUidMapChanges(0); StatsdStats::getInstance().setUidMapSnapshots(1); @@ -305,59 +331,103 @@ size_t UidMap::getBytesUsed() const { return mBytesUsed; } -UidMapping UidMap::getOutput(const ConfigKey& key) { - return getOutput(getElapsedRealtimeNs(), key); +void UidMap::appendUidMap(const ConfigKey& key, ProtoOutputStream* proto) { + appendUidMap(getElapsedRealtimeNs(), key, proto); } -UidMapping UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key) { +void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, + ProtoOutputStream* proto) { lock_guard lock(mMutex); // Lock for updates - auto ret = UidMapping(mOutput); // Copy that will be returned. + for (const ChangeRecord& record : mChanges) { + if (record.timestampNs > mLastUpdatePerConfigKey[key]) { + uint64_t changesToken = + proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CHANGES); + proto->write(FIELD_TYPE_BOOL | FIELD_ID_CHANGE_DELETION, (bool)record.deletion); + proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_TIMESTAMP, + (long long)record.timestampNs); + proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package); + proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid); + proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_VERSION, (int)record.version); + proto->end(changesToken); + } + } + + bool atLeastOneSnapshot = false; + unsigned int count = 0; + for (const SnapshotRecord& record : mSnapshots) { + // Ensure that we include at least the latest snapshot. + if ((count == mSnapshots.size() - 1 && !atLeastOneSnapshot) || + record.timestampNs > mLastUpdatePerConfigKey[key]) { + uint64_t snapshotsToken = + proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS); + atLeastOneSnapshot = true; + count++; + proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, + (long long)record.timestampNs); + proto->write(FIELD_TYPE_MESSAGE | FIELD_ID_SNAPSHOT_PACKAGE_INFO, record.bytes.data()); + proto->end(snapshotsToken); + } + } + int64_t prevMin = getMinimumTimestampNs(); mLastUpdatePerConfigKey[key] = timestamp; int64_t newMin = getMinimumTimestampNs(); - if (newMin > prevMin) { // Delete anything possible now that the minimum has moved forward. + if (newMin > prevMin) { // Delete anything possible now that the minimum has + // moved forward. int64_t cutoff_nanos = newMin; - auto snapshots = mOutput.mutable_snapshots(); - auto it_snapshots = snapshots->cbegin(); - while (it_snapshots != snapshots->cend()) { - if (it_snapshots->elapsed_timestamp_nanos() < cutoff_nanos) { - // it_snapshots points to the following element after erasing. - it_snapshots = snapshots->erase(it_snapshots); + for (auto it_snapshots = mSnapshots.begin(); it_snapshots != mSnapshots.end();) { + if (it_snapshots->timestampNs < cutoff_nanos) { + mBytesUsed -= it_snapshots->bytes.size() + kBytesTimestampField; + it_snapshots = mSnapshots.erase(it_snapshots); } else { ++it_snapshots; } } - auto deltas = mOutput.mutable_changes(); - auto it_deltas = deltas->cbegin(); - while (it_deltas != deltas->cend()) { - if (it_deltas->elapsed_timestamp_nanos() < cutoff_nanos) { - // it_snapshots points to the following element after erasing. - it_deltas = deltas->erase(it_deltas); + for (auto it_changes = mChanges.begin(); it_changes != mChanges.end();) { + if (it_changes->timestampNs < cutoff_nanos) { + mBytesUsed -= kBytesChangeRecord; + it_changes = mChanges.erase(it_changes); } else { - ++it_deltas; + ++it_changes; } } - if (mOutput.snapshots_size() == 0) { - // Produce another snapshot. This results in extra data being uploaded but helps - // ensure we can re-construct the UID->app name, versionCode mapping in server. - auto snapshot = mOutput.add_snapshots(); - snapshot->set_elapsed_timestamp_nanos(timestamp); - for (auto it : mMap) { - auto t = snapshot->add_package_info(); - t->set_name(it.second.packageName); - t->set_version(it.second.versionCode); - t->set_uid(it.first); + if (mSnapshots.size() == 0) { + // Produce another snapshot. This results in extra data being uploaded but + // helps ensure we can re-construct the UID->app name, versionCode mapping + // in server. + ProtoOutputStream snapshotProto; + uint64_t token = snapshotProto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | + FIELD_ID_SNAPSHOT_PACKAGE_INFO); + for (const auto& it : mMap) { + snapshotProto.write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, + it.second.packageName); + snapshotProto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, + (int)it.second.versionCode); + snapshotProto.write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, + (int)it.first); + } + snapshotProto.end(token); + + // Copy ProtoOutputStream output to + auto iter = snapshotProto.data(); + vector snapshotData(snapshotProto.size()); + size_t pos = 0; + while (iter.readBuffer() != NULL) { + size_t toRead = iter.currentToRead(); + std::memcpy(&(snapshotData[pos]), iter.readBuffer(), toRead); + pos += toRead; + iter.rp()->move(toRead); } + mSnapshots.emplace_back(timestamp, snapshotData); + mBytesUsed += kBytesTimestampField + snapshotData.size(); } } - mBytesUsed = mOutput.ByteSize(); // Compute actual size after potential deletions. StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); - StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size()); - StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size()); - return ret; + StatsdStats::getInstance().setUidMapChanges(mChanges.size()); + StatsdStats::getInstance().setUidMapSnapshots(mSnapshots.size()); } void UidMap::printUidMap(FILE* out) const { @@ -374,7 +444,7 @@ void UidMap::OnConfigUpdated(const ConfigKey& key) { // Ensure there is at least one snapshot available since this configuration also needs to know // what all the uid's represent. - if (mOutput.snapshots_size() == 0) { + if (mSnapshots.size() == 0) { sp statsCompanion = nullptr; // Get statscompanion service from service manager const sp sm(defaultServiceManager()); diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h index c41e0aaca3d229a710024e2970d27c042c4623ef..9dc73f4859c69efa90801e29215ec6710c980691 100644 --- a/cmds/statsd/src/packages/UidMap.h +++ b/cmds/statsd/src/packages/UidMap.h @@ -18,8 +18,8 @@ #include "config/ConfigKey.h" #include "config/ConfigListener.h" -#include "frameworks/base/cmds/statsd/src/stats_log_common.pb.h" #include "packages/PackageInfoListener.h" +#include "stats_util.h" #include #include @@ -27,13 +27,17 @@ #include #include #include +#include #include #include #include #include +using namespace android; using namespace std; +using android::util::ProtoOutputStream; + namespace android { namespace os { namespace statsd { @@ -45,6 +49,45 @@ struct AppData { AppData(const string& a, const int64_t v) : packageName(a), versionCode(v){}; }; +// When calling appendUidMap, we retrieve all the ChangeRecords since the last +// timestamp we called appendUidMap for this configuration key. +struct ChangeRecord { + const bool deletion; + const int64_t timestampNs; + const string package; + const int32_t uid; + const int32_t version; + + ChangeRecord(const bool isDeletion, const int64_t timestampNs, const string& package, + const int32_t uid, const int32_t version) + : deletion(isDeletion), + timestampNs(timestampNs), + package(package), + uid(uid), + version(version) { + } +}; + +const unsigned int kBytesChangeRecord = sizeof(struct ChangeRecord); + +// Storing the int64 for a timestamp is expected to take 10 bytes (could take +// less because of varint encoding). +const unsigned int kBytesTimestampField = 10; + +// When calling appendUidMap, we retrieve all the snapshots since the last +// timestamp we called appendUidMap for this configuration key. +struct SnapshotRecord { + const int64_t timestampNs; + + // For performance reasons, we convert the package_info field (which is a + // repeated field of PackageInfo messages). + vector bytes; + + SnapshotRecord(const int64_t timestampNs, vector bytes) + : timestampNs(timestampNs), bytes(bytes) { + } +}; + // UidMap keeps track of what the corresponding app name (APK name) and version code for every uid // at any given moment. This map must be updated by StatsCompanionService. class UidMap : public virtual android::RefBase { @@ -93,8 +136,10 @@ public: // Returns the host uid if it exists. Otherwise, returns the same uid that was passed-in. virtual int getHostUidOrSelf(int uid) const; - // Gets the output. If every config key has received the output, then the output is cleared. - UidMapping getOutput(const ConfigKey& key); + // Gets all snapshots and changes that have occurred since the last output. + // If every config key has received a change or snapshot record, then this + // record is deleted. + void appendUidMap(const ConfigKey& key, util::ProtoOutputStream* proto); // Forces the output to be cleared. We still generate a snapshot based on the current state. // This results in extra data uploaded but helps us reconstruct the uid mapping on the server @@ -117,7 +162,8 @@ private: const int64_t& versionCode); void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid); - UidMapping getOutput(const int64_t& timestamp, const ConfigKey& key); + void appendUidMap(const int64_t& timestamp, const ConfigKey& key, + util::ProtoOutputStream* proto); void getListenerListCopyLocked(std::vector>* output); @@ -133,8 +179,11 @@ private: // to the parent uid. std::unordered_map mIsolatedUidMap; - // We prepare the output proto as apps are updated, so that we can grab the current output. - UidMapping mOutput; + // Record the changes that can be provided with the uploads. + std::list mChanges; + + // Record the snapshots that can be provided with the uploads. + std::list mSnapshots; // Metric producers that should be notified if there's an upgrade in any app. set> mSubscribers; diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 3c5f5a2b9907afc0f10f383a5c91290edb94bf44..dd3b37c8c2d77a6cb5bb8fe2a5d27cd2de035c57 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -22,7 +22,6 @@ option java_package = "com.android.os"; option java_outer_classname = "StatsLog"; import "frameworks/base/cmds/statsd/src/atoms.proto"; -import "frameworks/base/cmds/statsd/src/stats_log_common.proto"; message DimensionsValue { optional int32 field = 1; @@ -46,7 +45,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 +104,8 @@ message GaugeBucketInfo { repeated Atom atom = 3; repeated int64 elapsed_timestamp_nanos = 4; + + repeated int64 wall_clock_timestamp_nanos = 5; } message GaugeMetricData { @@ -146,6 +147,33 @@ message StatsLogReport { } } +message UidMapping { + message PackageInfoSnapshot { + message PackageInfo { + optional string name = 1; + + optional int64 version = 2; + + optional int32 uid = 3; + } + optional int64 elapsed_timestamp_nanos = 1; + + repeated PackageInfo package_info = 2; + } + repeated PackageInfoSnapshot snapshots = 1; + + message Change { + optional bool deletion = 1; + + optional int64 elapsed_timestamp_nanos = 2; + optional string app = 3; + optional int32 uid = 4; + + optional int64 version = 5; + } + repeated Change changes = 2; +} + message ConfigMetricsReport { repeated StatsLogReport metrics = 1; @@ -154,6 +182,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/stats_log_common.proto b/cmds/statsd/src/stats_log_common.proto deleted file mode 100644 index c41f31ebaa3f951f539cf951552a00aa9c82e5af..0000000000000000000000000000000000000000 --- a/cmds/statsd/src/stats_log_common.proto +++ /dev/null @@ -1,49 +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. - */ - -syntax = "proto2"; - -package android.os.statsd; - -option java_package = "com.android.os"; -option java_outer_classname = "StatsLogCommon"; - -message UidMapping { - message PackageInfoSnapshot { - message PackageInfo { - optional string name = 1; - - optional int64 version = 2; - - optional int32 uid = 3; - } - optional int64 elapsed_timestamp_nanos = 1; - - repeated PackageInfo package_info = 2; - } - repeated PackageInfoSnapshot snapshots = 1; - - message Change { - optional bool deletion = 1; - - optional int64 elapsed_timestamp_nanos = 2; - optional string app = 3; - optional int32 uid = 4; - - optional int64 version = 5; - } - repeated Change changes = 2; -} \ No newline at end of file diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h index c512e3c63bcfc1842c522137000e2b6f1d2d67b8..97220500073d2a4c05a880d80105889f70281240 100644 --- a/cmds/statsd/src/stats_log_util.h +++ b/cmds/statsd/src/stats_log_util.h @@ -19,7 +19,6 @@ #include #include "FieldValue.h" #include "HashableDimensionKey.h" -#include "frameworks/base/cmds/statsd/src/stats_log_common.pb.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "guardrail/StatsdStats.h" diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h index 80e46d604b2180598880f9e2066dfb60b290ab04..e0206d10e6ade6b557708aa5c1f7683026191e31 100644 --- a/cmds/statsd/src/stats_util.h +++ b/cmds/statsd/src/stats_util.h @@ -17,7 +17,6 @@ #pragma once #include "HashableDimensionKey.h" -#include "frameworks/base/cmds/statsd/src/stats_log_common.pb.h" #include "logd/LogReader.h" #include diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index 1e8aa12112bc7f4fc97b754cf2487edb832d2a5c..2c701915f42980fd3149ed6106205e10fed6f197 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 { @@ -295,6 +297,7 @@ message PerfettoDetails { message BroadcastSubscriberDetails { optional int64 subscriber_id = 1; + repeated string cookie = 2; } message Subscription { diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp index 781ecede1700e625503509eb7d360a0f8d5f7ea0..3d8aa475c11b90d6e3e3bd5f9c08e455eab1226c 100644 --- a/cmds/statsd/src/storage/StorageManager.cpp +++ b/cmds/statsd/src/storage/StorageManager.cpp @@ -160,38 +160,46 @@ void StorageManager::sendBroadcast(const char* path, } } -void StorageManager::appendConfigMetricsReport(ProtoOutputStream& proto) { +void StorageManager::appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto) { unique_ptr dir(opendir(STATS_DATA_DIR), closedir); if (dir == NULL) { VLOG("Path %s does not exist", STATS_DATA_DIR); return; } + 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; - VLOG("file %s", name); - 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]; - string file_name = getFilePath(STATS_DATA_DIR, timestamp, uid, configID); - int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC); - if (fd != -1) { - string content; - if (android::base::ReadFdToString(fd, &content)) { - proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS, - content.c_str()); + size_t nameLen = strlen(name); + size_t suffixLen = strlen(suffix); + if (suffixLen <= nameLen && + strncmp(name + nameLen - suffixLen, suffix, suffixLen) == 0) { + 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]; + + string file_name = getFilePath(STATS_DATA_DIR, timestamp, uid, configID); + int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC); + if (fd != -1) { + string content; + if (android::base::ReadFdToString(fd, &content)) { + proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS, + content.c_str(), content.size()); + } + close(fd); } - close(fd); - } - // Remove file from disk after reading. - remove(file_name.c_str()); + // Remove file from disk after reading. + remove(file_name.c_str()); + } } } @@ -245,6 +253,47 @@ void StorageManager::readConfigFromDisk(map& configsMap } } +bool StorageManager::hasIdenticalConfig(const ConfigKey& key, + const vector& config) { + unique_ptr 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 vec(content.begin(), content.end()); + if (vec == config) { + close(fd); + return true; + } + } + close(fd); + } + } + } + return false; +} + void StorageManager::trimToFit(const char* path) { unique_ptr dir(opendir(path), closedir); if (dir == NULL) { @@ -306,6 +355,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(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 6c8ed0a967046a9b2ea5806b7778400ee77b2685..fb7b0853ec4c80dc0bc0bc3399e28b76b9b692da 100644 --- a/cmds/statsd/src/storage/StorageManager.h +++ b/cmds/statsd/src/storage/StorageManager.h @@ -66,7 +66,7 @@ public: * Appends ConfigMetricsReport found on disk to the specific proto and * delete it. */ - static void appendConfigMetricsReport(ProtoOutputStream& proto); + static void appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto); /** * Call to load the saved configs from disk. @@ -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& 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/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp index 95ecf8033f4c631a4a63158bca500ab9583cdc00..25d2257c752b7ce1a5fce15619c8f30520f26e5e 100644 --- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp +++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp @@ -77,6 +77,12 @@ void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey, } int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id(); + vector cookies; + cookies.reserve(subscription.broadcast_subscriber_details().cookie_size()); + for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) { + cookies.push_back(String16(cookie.c_str())); + } + auto it1 = mIntentMap.find(configKey); if (it1 == mIntentMap.end()) { ALOGW("Cannot inform subscriber for missing config key %s ", configKey.ToString().c_str()); @@ -88,12 +94,13 @@ void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey, configKey.ToString().c_str(), (long long)subscriberId); return; } - sendBroadcastLocked(it2->second, configKey, subscription, dimKey); + sendBroadcastLocked(it2->second, configKey, subscription, cookies, dimKey); } void SubscriberReporter::sendBroadcastLocked(const sp& intentSender, const ConfigKey& configKey, const Subscription& subscription, + const vector& cookies, const MetricDimensionKey& dimKey) const { VLOG("SubscriberReporter::sendBroadcastLocked called."); if (mStatsCompanionService == nullptr) { @@ -101,11 +108,16 @@ void SubscriberReporter::sendBroadcastLocked(const sp& intentSender, return; } mStatsCompanionService->sendSubscriberBroadcast( - intentSender, configKey.GetUid(), configKey.GetId(), subscription.id(), - subscription.rule_id(), getStatsDimensionsValue(dimKey.getDimensionKeyInWhat())); + intentSender, + configKey.GetUid(), + configKey.GetId(), + subscription.id(), + subscription.rule_id(), + cookies, + getStatsDimensionsValue(dimKey.getDimensionKeyInWhat())); } -void getStatsDimensionsValueHelper(const std::vector& dims, size_t* index, int depth, +void getStatsDimensionsValueHelper(const vector& dims, size_t* index, int depth, int prefix, vector* output) { size_t count = dims.size(); while (*index < count) { diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h index 50100df56ff8de92206ed7f8231474648f412387..2a7f771a0ba4c73390620945c48ed6ad2eb47572 100644 --- a/cmds/statsd/src/subscriber/SubscriberReporter.h +++ b/cmds/statsd/src/subscriber/SubscriberReporter.h @@ -26,6 +26,7 @@ #include #include +#include namespace android { namespace os { @@ -102,6 +103,7 @@ private: void sendBroadcastLocked(const sp& intentSender, const ConfigKey& configKey, const Subscription& subscription, + const std::vector& cookies, const MetricDimensionKey& dimKey) const; }; diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp index 5846761cb8e9884de0abc5b8a73d087f400cb6e6..73e7c44dc3da02fde407f711599fab0b43f02474 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 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 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/StatsService_test.cpp b/cmds/statsd/tests/StatsService_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a7b41366626601efd954dc223c5d7251efff76dc --- /dev/null +++ b/cmds/statsd/tests/StatsService_test.cpp @@ -0,0 +1,67 @@ +// 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 "StatsService.h" +#include "config/ConfigKey.h" +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" + +#include +#include + +#include + +using namespace android; +using namespace testing; + +namespace android { +namespace os { +namespace statsd { + +using android::util::ProtoOutputStream; + +#ifdef __ANDROID__ + +TEST(StatsServiceTest, TestAddConfig_simple) { + StatsService service(nullptr); + StatsdConfig config; + config.set_id(12345); + string serialized = config.SerializeAsString(); + + EXPECT_TRUE( + service.addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()})); +} + +TEST(StatsServiceTest, TestAddConfig_empty) { + StatsService service(nullptr); + string serialized = ""; + + EXPECT_TRUE( + service.addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()})); +} + +TEST(StatsServiceTest, TestAddConfig_invalid) { + StatsService service(nullptr); + string serialized = "Invalid config!"; + + EXPECT_FALSE( + service.addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()})); +} + +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp index ca656ed9ab354502ea8095ac73de342d5f0bb7cd..c9492eb609f9913915924cf3e6d9bcfe9bc0e340 100644 --- a/cmds/statsd/tests/UidMap_test.cpp +++ b/cmds/statsd/tests/UidMap_test.cpp @@ -20,6 +20,7 @@ #include "statslog.h" #include "statsd_test_util.h" +#include #include #include @@ -30,6 +31,8 @@ namespace android { namespace os { namespace statsd { +using android::util::ProtoOutputStream; + #ifdef __ANDROID__ const string kApp1 = "app1.sharing.1"; const string kApp2 = "app2.sharing.1"; @@ -156,6 +159,20 @@ TEST(UidMapTest, TestUpdateApp) { EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end()); } +static void protoOutputStreamToUidMapping(ProtoOutputStream* proto, UidMapping* results) { + vector bytes; + bytes.resize(proto->size()); + size_t pos = 0; + auto iter = proto->data(); + while (iter.readBuffer() != NULL) { + size_t toRead = iter.currentToRead(); + std::memcpy(&((bytes)[pos]), iter.readBuffer(), toRead); + pos += toRead; + iter.rp()->move(toRead); + } + results->ParseFromArray(bytes.data(), bytes.size()); +} + TEST(UidMapTest, TestClearingOutput) { UidMap m; @@ -174,41 +191,52 @@ TEST(UidMapTest, TestClearingOutput) { versions.push_back(4); versions.push_back(5); m.updateMap(1, uids, versions, apps); - EXPECT_EQ(1, m.mOutput.snapshots_size()); + EXPECT_EQ(1U, m.mSnapshots.size()); - UidMapping results = m.getOutput(2, config1); + ProtoOutputStream proto; + m.appendUidMap(2, config1, &proto); + UidMapping results; + protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); // It should be cleared now - EXPECT_EQ(1, m.mOutput.snapshots_size()); - results = m.getOutput(3, config1); + EXPECT_EQ(1U, m.mSnapshots.size()); + proto.clear(); + m.appendUidMap(2, config1, &proto); + protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); // Now add another configuration. m.OnConfigUpdated(config2); m.updateApp(5, String16(kApp1.c_str()), 1000, 40); - EXPECT_EQ(1, m.mOutput.changes_size()); - results = m.getOutput(6, config1); + EXPECT_EQ(1U, m.mChanges.size()); + proto.clear(); + m.appendUidMap(6, config1, &proto); + protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); EXPECT_EQ(1, results.changes_size()); - EXPECT_EQ(1, m.mOutput.changes_size()); + EXPECT_EQ(1U, m.mChanges.size()); // Add another delta update. m.updateApp(7, String16(kApp2.c_str()), 1001, 41); - EXPECT_EQ(2, m.mOutput.changes_size()); + EXPECT_EQ(2U, m.mChanges.size()); // We still can't remove anything. - results = m.getOutput(8, config1); + proto.clear(); + m.appendUidMap(8, config1, &proto); + protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); - EXPECT_EQ(2, results.changes_size()); - EXPECT_EQ(2, m.mOutput.changes_size()); + EXPECT_EQ(1, results.changes_size()); + EXPECT_EQ(2U, m.mChanges.size()); - results = m.getOutput(9, config2); + proto.clear(); + m.appendUidMap(9, config2, &proto); + protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); EXPECT_EQ(2, results.changes_size()); // At this point both should be cleared. - EXPECT_EQ(1, m.mOutput.snapshots_size()); - EXPECT_EQ(0, m.mOutput.changes_size()); + EXPECT_EQ(1U, m.mSnapshots.size()); + EXPECT_EQ(0U, m.mChanges.size()); } TEST(UidMapTest, TestMemoryComputed) { @@ -231,10 +259,12 @@ TEST(UidMapTest, TestMemoryComputed) { m.updateApp(3, String16(kApp1.c_str()), 1000, 40); EXPECT_TRUE(m.mBytesUsed > snapshot_bytes); - m.getOutput(2, config1); + ProtoOutputStream proto; + vector bytes; + m.appendUidMap(2, config1, &proto); size_t prevBytes = m.mBytesUsed; - m.getOutput(4, config1); + m.appendUidMap(4, config1, &proto); EXPECT_TRUE(m.mBytesUsed < prevBytes); } @@ -256,17 +286,17 @@ TEST(UidMapTest, TestMemoryGuardrail) { versions.push_back(1); } m.updateMap(1, uids, versions, apps); - EXPECT_EQ(1, m.mOutput.snapshots_size()); + EXPECT_EQ(1U, m.mSnapshots.size()); m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2); - EXPECT_EQ(1, m.mOutput.snapshots_size()); - EXPECT_EQ(1, m.mOutput.changes_size()); + EXPECT_EQ(1U, m.mSnapshots.size()); + EXPECT_EQ(1U, m.mChanges.size()); // Now force deletion by limiting the memory to hold one delta change. m.maxBytesOverride = 80; // Since the app string alone requires >45 characters. m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4); - EXPECT_EQ(0, m.mOutput.snapshots_size()); - EXPECT_EQ(1, m.mOutput.changes_size()); + EXPECT_EQ(0U, m.mSnapshots.size()); + EXPECT_EQ(1U, m.mChanges.size()); } #else GTEST_LOG_(INFO) << "This test does nothing.\n"; @@ -274,4 +304,4 @@ GTEST_LOG_(INFO) << "This test does nothing.\n"; } // namespace statsd } // namespace os -} // namespace android \ No newline at end of file +} // namespace android diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp index b4a7bb706029437688cecd789bd1b5d40ee72783..218d52a5c04677f95e73f24ce910b761ebf1445b 100644 --- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp +++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp @@ -16,6 +16,7 @@ #include "../metrics/metrics_test_helper.h" #include +#include #include #include @@ -104,12 +105,12 @@ void checkRefractoryTimes(AnomalyTracker& tracker, for (const auto& kv : timestamps) { if (kv.second < 0) { // Make sure that, if there is a refractory period, it is already past. - EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first), - currTimestampNs / NS_PER_SEC + 1) + EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first) * NS_PER_SEC, + (uint64_t)currTimestampNs) << "Failure was at currTimestampNs " << currTimestampNs; } else { EXPECT_EQ(tracker.getRefractoryPeriodEndsSec(kv.first), - kv.second / NS_PER_SEC + refractoryPeriodSec) + std::ceil(1.0 * kv.second / NS_PER_SEC) + refractoryPeriodSec) << "Failure was at currTimestampNs " << currTimestampNs; } } diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp index 7a7e000fb98ff5686ffbbe33a99e7a61e55d0057..a04a6f91463372c00f1d166f008f82247ca3d594 100644 --- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp @@ -28,8 +28,9 @@ namespace statsd { namespace { -StatsdConfig CreateStatsdConfig() { +StatsdConfig CreateStatsdConfig(const Position position) { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher(); auto attributionNodeMatcher = wakelockAcquireMatcher.mutable_simple_atom_matcher()->add_field_value_matcher(); @@ -46,15 +47,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 +200,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 attributions1 = {CreateAttribution(111, "App1"), + CreateAttribution(222, "GMSCoreModule1"), + CreateAttribution(333, "App3")}; + + // GMS core node is the last one. + std::vector attributions2 = {CreateAttribution(111, "App1"), + CreateAttribution(333, "App3"), + CreateAttribution(222, "GMSCoreModule1")}; + + // GMS core node is the first one. + std::vector attributions3 = {CreateAttribution(222, "GMSCoreModule1"), + CreateAttribution(333, "App3")}; + + // Single GMS core node. + std::vector attributions4 = {CreateAttribution(222, "GMSCoreModule1")}; + + // GMS core has another uid. + std::vector attributions5 = {CreateAttribution(111, "App1"), + CreateAttribution(444, "GMSCoreModule2"), + CreateAttribution(333, "App3")}; + + // Multiple GMS core nodes. + std::vector attributions6 = {CreateAttribution(444, "GMSCoreModule2"), + CreateAttribution(222, "GMSCoreModule1")}; + + // No GMS core nodes. + std::vector attributions7 = {CreateAttribution(111, "App1"), + CreateAttribution(333, "App3")}; + std::vector attributions8 = {CreateAttribution(111, "App1")}; + + // GMS core node with isolated uid. + const int isolatedUid = 666; + std::vector attributions9 = { + CreateAttribution(isolatedUid, "GMSCoreModule1")}; + + std::vector> 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 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/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp index a08f6067c96c27d05e51cada655830baac53bde5..63e23ce3a941647ca629031d524fa87b49c66fb0 100644 --- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp +++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp @@ -31,6 +31,7 @@ namespace { StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition( DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); @@ -337,6 +338,7 @@ namespace { StatsdConfig CreateDurationMetricConfig_Link_AND_CombinationCondition( DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); @@ -580,6 +582,7 @@ namespace { StatsdConfig CreateDurationMetricConfig_PartialLink_AND_CombinationCondition( DurationMetric::AggregationType aggregationType) { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp index 435e1991b9e36402ef928ef3a9256cf54c5825f8..2287c2bfc8903395d8a4d694f9e548df4e3660e0 100644 --- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp +++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp @@ -30,6 +30,7 @@ namespace { StatsdConfig CreateCountMetric_NoLink_CombinationCondition_Config() { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. auto screenBrightnessChangeAtomMatcher = CreateScreenBrightnessChangedAtomMatcher(); *config.add_atom_matcher() = screenBrightnessChangeAtomMatcher; *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); @@ -229,6 +230,7 @@ namespace { StatsdConfig CreateCountMetric_Link_CombinationCondition() { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. auto appCrashMatcher = CreateProcessCrashAtomMatcher(); *config.add_atom_matcher() = appCrashMatcher; *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); @@ -416,6 +418,7 @@ namespace { StatsdConfig CreateDurationMetricConfig_NoLink_CombinationCondition( DurationMetric::AggregationType aggregationType) { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher(); *config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher(); *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); @@ -603,6 +606,7 @@ namespace { StatsdConfig CreateDurationMetricConfig_Link_CombinationCondition( DurationMetric::AggregationType aggregationType) { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp index 75ceafb489b3ec7b6537098c206876926987dde0..ab37140577af7b39ffaf6098d6735e0aa58c2469 100644 --- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp +++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp @@ -31,6 +31,7 @@ namespace { StatsdConfig CreateDurationMetricConfig_NoLink_SimpleCondition( DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); @@ -306,6 +307,7 @@ namespace { StatsdConfig createDurationMetric_Link_SimpleConditionConfig( DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); @@ -525,6 +527,7 @@ namespace { StatsdConfig createDurationMetric_PartialLink_SimpleConditionConfig( DurationMetric::AggregationType aggregationType) { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher(); *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); 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 0000000000000000000000000000000000000000..2e6a0f05a3412f782172ecd1a4bd527b58698eb4 --- /dev/null +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp @@ -0,0 +1,282 @@ +// 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 + +#include "src/StatsLogProcessor.h" +#include "src/stats_log_util.h" +#include "tests/statsd_test_util.h" + +#include + +namespace android { +namespace os { +namespace statsd { + +#ifdef __ANDROID__ + +namespace { + +StatsdConfig CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sampling_type) { + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); + *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); + + 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 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( + 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> 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 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 3843e0a3c67d7bbb6e5a19c1120f904b655c706a..0000000000000000000000000000000000000000 --- 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 - -#include "src/StatsLogProcessor.h" -#include "src/stats_log_util.h" -#include "tests/statsd_test_util.h" - -#include - -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 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( - 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> 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 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/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp index c874d92a1b019b21ae2604b3cc695c550d16b4d7..1440f2941c05d2116999f4d8d868deb18ec59d49 100644 --- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp @@ -29,6 +29,8 @@ namespace { StatsdConfig CreateStatsdConfig() { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher(); diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp index 9153795365a2081e02ad94679a600929d59a7fca..bfae8bca697f32e4f8c5854ffda6fabcad7f6c6a 100644 --- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp @@ -30,6 +30,7 @@ namespace { StatsdConfig CreateStatsdConfig(DurationMetric::AggregationType aggregationType) { StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher(); *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher(); diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp index a07683e5b0455fa7c39371ee9f911586710a4acd..fff11552df40ae2d15a7ff48ccc9473a50f1b273 100644 --- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -379,13 +380,13 @@ TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) { EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second); // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6 EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), - event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec); + std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7); EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size()); EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second); EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), - event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec); + std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); } } // namespace statsd diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp index 77b3ace90aff9cfd4b5d1ca0bb7d4a0968db62dd..5ef84e6ac6ce90aa168417e20ce382c91650350c 100644 --- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -112,7 +113,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 +125,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 +336,6 @@ TEST(GaugeMetricProducerTest, TestWithCondition) { .mGaugeAtoms.front() .mFields->begin() ->mValue.int_value); - EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum); } TEST(GaugeMetricProducerTest, TestAnomalyDetection) { @@ -395,7 +393,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) { .mFields->begin() ->mValue.int_value); EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), - event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec); + std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec); std::shared_ptr event3 = std::make_shared(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10); @@ -410,7 +408,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) { .mFields->begin() ->mValue.int_value); EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), - event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec); + std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); // The event4 does not have the gauge field. Thus the current bucket value is 0. std::shared_ptr event4 = diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp index 54abcb28a44926b01ec66a84e756ad090c54993b..9b27f3cde3bd315ce618deff240b8fbeaf82951f 100644 --- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp +++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -416,7 +417,7 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) { tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 25, false); EXPECT_EQ(anomalyTracker->getSumOverPastBuckets(eventKey), (long long)(bucketSizeNs)); EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), - (eventStartTimeNs + 2 * bucketSizeNs + 25) / NS_PER_SEC + refPeriodSec); + std::ceil((eventStartTimeNs + 2 * bucketSizeNs + 25.0) / NS_PER_SEC + refPeriodSec)); } TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) { diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index a0addcccb7a1d12f418746a1e892df5a7f009679..a8eb27037ebf0294a005a0ab39a12f6e98b87d2e 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -415,16 +416,16 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) { valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4); // Anomaly at event 4 since Value sum == 131 > 130! EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), - event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec); + std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5); // Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4. EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), - event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec); + std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6); // Anomaly at event 6 since Value sum == 160 > 130 and after refractory period. EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), - event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec); + std::ceil(1.0 * event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); } } // namespace statsd diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index 2678c8a93463c32dff73f36614ae0c2168c44d12..0f785dff8e812b84ac34fcf9dbfde1a991f02a98 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 14eba1f67d9d141785ba7d478f57f9f0712e15cc..1ac630ccff964cc784c588f19ef7a0a0d7035eb1 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> *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 1a1d431b1d2dbd01ceec1775e9882ed21f92ed0c..e2121dd486792cc3ca97793fa1e059ecf6ca3992 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -11,11 +11,13 @@ Landroid/app/ActivityManager;->clearApplicationUserData(Ljava/lang/String;Landro Landroid/app/ActivityManager;->getMaxRecentTasksStatic()I Landroid/app/ActivityManager;->getService()Landroid/app/IActivityManager; Landroid/app/ActivityManager;->IActivityManagerSingleton:Landroid/util/Singleton; +Landroid/app/ActivityManager;->isHighEndGfx()Z Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z Landroid/app/ActivityManager;->isUserRunning(I)Z Landroid/app/ActivityManager;->mContext:Landroid/content/Context; Landroid/app/ActivityManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager; Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager; +Landroid/app/ActivityManager;->PROCESS_STATE_IMPORTANT_BACKGROUND:I Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I Landroid/app/ActivityManager$RecentTaskInfo;->firstActiveTime:J Landroid/app/ActivityManager$RunningAppProcessInfo;->flags:I @@ -95,6 +97,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 @@ -114,6 +117,8 @@ Landroid/app/admin/DevicePolicyManager;->getTrustAgentConfiguration(Landroid/con Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/String;I)Z Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V +Landroid/app/admin/DevicePolicyManager;->setDefaultSmsApplication(Landroid/content/ComponentName;Ljava/lang/String;)V +Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(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;->([B)V @@ -143,6 +148,7 @@ Landroid/app/Application;->mComponentCallbacks:Ljava/util/ArrayList; Landroid/app/Application;->mLoadedApk:Landroid/app/LoadedApk; Landroid/app/ApplicationPackageManager;->configurationChanged()V Landroid/app/ApplicationPackageManager;->deletePackage(Ljava/lang/String;Landroid/content/pm/IPackageDeleteObserver;I)V +Landroid/app/ApplicationPackageManager;->getPackageCurrentVolume(Landroid/content/pm/ApplicationInfo;)Landroid/os/storage/VolumeInfo; Landroid/app/ApplicationPackageManager;->getPackageSizeInfoAsUser(Ljava/lang/String;ILandroid/content/pm/IPackageStatsObserver;)V Landroid/app/ApplicationPackageManager;->(Landroid/app/ContextImpl;Landroid/content/pm/IPackageManager;)V Landroid/app/ApplicationPackageManager;->mPM:Landroid/content/pm/IPackageManager; @@ -170,6 +176,7 @@ Landroid/app/backup/BackupHelperDispatcher$Header;->chunkSize:I Landroid/app/backup/BackupHelperDispatcher$Header;->keyPrefix:Ljava/lang/String; Landroid/app/backup/FullBackup;->backupToTar(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/FullBackupDataOutput;)I Landroid/app/backup/FullBackupDataOutput;->addSize(J)V +Landroid/app/backup/FullBackupDataOutput;->(Landroid/os/ParcelFileDescriptor;)V Landroid/app/backup/FullBackupDataOutput;->mData:Landroid/app/backup/BackupDataOutput; Landroid/app/ContentProviderHolder;->info:Landroid/content/pm/ProviderInfo; Landroid/app/ContentProviderHolder;->(Landroid/content/pm/ProviderInfo;)V @@ -228,6 +235,7 @@ Landroid/app/IAlarmManager$Stub;->TRANSACTION_set:I Landroid/app/IApplicationThread;->scheduleTrimMemory(I)V Landroid/app/INotificationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/INotificationManager; Landroid/app/INotificationManager$Stub$Proxy;->(Landroid/os/IBinder;)V +Landroid/app/Instrumentation;->execStartActivities(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Landroid/app/Activity;[Landroid/content/Intent;Landroid/os/Bundle;)V Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Landroid/app/Activity;Landroid/content/Intent;ILandroid/os/Bundle;)Landroid/app/Instrumentation$ActivityResult; Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;)Landroid/app/Instrumentation$ActivityResult; Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;Landroid/os/UserHandle;)Landroid/app/Instrumentation$ActivityResult; @@ -275,6 +283,7 @@ Landroid/app/Notification;->mGroupKey:Ljava/lang/String; Landroid/app/Notification;->mLargeIcon:Landroid/graphics/drawable/Icon; Landroid/app/Notification;->mSmallIcon:Landroid/graphics/drawable/Icon; Landroid/app/Notification;->setLatestEventInfo(Landroid/content/Context;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/app/PendingIntent;)V +Landroid/app/Notification;->setSmallIcon(Landroid/graphics/drawable/Icon;)V Landroid/app/PendingIntent;->getActivityAsUser(Landroid/content/Context;ILandroid/content/Intent;ILandroid/os/Bundle;Landroid/os/UserHandle;)Landroid/app/PendingIntent; Landroid/app/PendingIntent;->getIntent()Landroid/content/Intent; Landroid/app/PendingIntent;->isActivity()Z @@ -307,6 +316,7 @@ Landroid/app/TimePickerDialog;->mTimePicker:Landroid/widget/TimePicker; Landroid/app/trust/ITrustManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/app/usage/UsageStatsManager;->mService:Landroid/app/usage/IUsageStatsManager; Landroid/app/usage/UsageStats;->mLastEvent:I +Landroid/app/usage/UsageStats;->mTotalTimeInForeground:J Landroid/app/WallpaperColors;->getColorHints()I Landroid/app/WallpaperManager;->getBitmap()Landroid/graphics/Bitmap; Landroid/app/WallpaperManager;->getBitmap(Z)Landroid/graphics/Bitmap; @@ -320,7 +330,9 @@ Landroid/appwidget/AppWidgetManager;->bindAppWidgetId(ILandroid/content/Componen Landroid/appwidget/AppWidgetManager;->mService:Lcom/android/internal/appwidget/IAppWidgetService; Landroid/bluetooth/BluetoothA2dp;->connect(Landroid/bluetooth/BluetoothDevice;)Z Landroid/bluetooth/BluetoothAdapter;->disable(Z)Z +Landroid/bluetooth/BluetoothAdapter;->factoryReset()Z Landroid/bluetooth/BluetoothAdapter;->getDiscoverableTimeout()I +Landroid/bluetooth/BluetoothAdapter;->getLeState()I Landroid/bluetooth/BluetoothAdapter;->mService:Landroid/bluetooth/IBluetooth; Landroid/bluetooth/BluetoothAdapter;->setScanMode(II)Z Landroid/bluetooth/BluetoothAdapter;->setScanMode(I)Z @@ -330,18 +342,23 @@ Landroid/bluetooth/BluetoothGattCharacteristic;->mInstance:I Landroid/bluetooth/BluetoothGattCharacteristic;->mService:Landroid/bluetooth/BluetoothGattService; Landroid/bluetooth/BluetoothGattDescriptor;->mCharacteristic:Landroid/bluetooth/BluetoothGattCharacteristic; Landroid/bluetooth/BluetoothGattDescriptor;->mInstance:I +Landroid/bluetooth/BluetoothGatt;->mAuthRetryState:I Landroid/bluetooth/BluetoothGatt;->refresh()Z Landroid/bluetooth/BluetoothHeadset;->close()V +Landroid/bluetooth/BluetoothPan;->isTetheringOn()Z +Landroid/bluetooth/BluetoothPan;->setBluetoothTethering(Z)V Landroid/bluetooth/BluetoothUuid;->RESERVED_UUIDS:[Landroid/os/ParcelUuid; Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String; Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth; Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String; +Landroid/bluetooth/le/ScanRecord;->parseFromBytes([B)Landroid/bluetooth/le/ScanRecord; Landroid/content/AsyncTaskLoader;->mExecutor:Ljava/util/concurrent/Executor; Landroid/content/BroadcastReceiver$PendingResult;->(ILjava/lang/String;Landroid/os/Bundle;IZZLandroid/os/IBinder;II)V Landroid/content/BroadcastReceiver;->setPendingResult(Landroid/content/BroadcastReceiver$PendingResult;)V Landroid/content/ContentProviderClient;->mContentProvider:Landroid/content/IContentProvider; Landroid/content/ContentProviderClient;->mPackageName:Ljava/lang/String; +Landroid/content/ContentProvider;->coerceToLocalContentProvider(Landroid/content/IContentProvider;)Landroid/content/ContentProvider; Landroid/content/ContentProvider;->mContext:Landroid/content/Context; Landroid/content/ContentProvider;->mPathPermissions:[Landroid/content/pm/PathPermission; Landroid/content/ContentProvider;->mReadPermission:Ljava/lang/String; @@ -351,11 +368,19 @@ Landroid/content/ContentProviderOperation;->mType:I Landroid/content/ContentProviderOperation;->TYPE_DELETE:I Landroid/content/ContentProviderOperation;->TYPE_INSERT:I Landroid/content/ContentProviderOperation;->TYPE_UPDATE:I +Landroid/content/ContentProvider;->setAppOps(II)V +Landroid/content/ContentResolver;->acquireExistingProvider(Landroid/content/Context;Ljava/lang/String;)Landroid/content/IContentProvider; +Landroid/content/ContentResolver;->acquireProvider(Landroid/content/Context;Ljava/lang/String;)Landroid/content/IContentProvider; Landroid/content/ContentResolver;->acquireProvider(Landroid/net/Uri;)Landroid/content/IContentProvider; +Landroid/content/ContentResolver;->acquireProvider(Ljava/lang/String;)Landroid/content/IContentProvider; +Landroid/content/ContentResolver;->acquireUnstableProvider(Landroid/content/Context;Ljava/lang/String;)Landroid/content/IContentProvider; Landroid/content/ContentResolver;->getContentService()Landroid/content/IContentService; Landroid/content/ContentResolver;->getSyncStatus(Landroid/accounts/Account;Ljava/lang/String;)Landroid/content/SyncStatusInfo; Landroid/content/ContentResolver;->mContext:Landroid/content/Context; Landroid/content/ContentResolver;->mPackageName:Ljava/lang/String; +Landroid/content/ContentResolver;->releaseProvider(Landroid/content/IContentProvider;)Z +Landroid/content/ContentResolver;->releaseUnstableProvider(Landroid/content/IContentProvider;)Z +Landroid/content/ContentResolver;->unstableProviderDied(Landroid/content/IContentProvider;)V Landroid/content/ContentValues;->(Ljava/util/HashMap;)V Landroid/content/ContentValues;->mValues:Ljava/util/HashMap; Landroid/content/Context;->getSharedPrefsFile(Ljava/lang/String;)Ljava/io/File; @@ -388,6 +413,7 @@ Landroid/content/pm/ApplicationInfo;->privateFlags:I Landroid/content/pm/ApplicationInfo;->scanPublicSourceDir:Ljava/lang/String; Landroid/content/pm/ApplicationInfo;->scanSourceDir:Ljava/lang/String; Landroid/content/pm/ApplicationInfo;->secondaryNativeLibraryDir:Ljava/lang/String; +Landroid/content/pm/ComponentInfo;->getComponentName()Landroid/content/ComponentName; Landroid/content/pm/IPackageManager;->getInstallLocation()I Landroid/content/pm/IPackageManager;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo; Landroid/content/pm/IPackageManager;->setApplicationEnabledSetting(Ljava/lang/String;IIILjava/lang/String;)V @@ -401,6 +427,7 @@ Landroid/content/pm/IPackageStatsObserver$Stub;->()V Landroid/content/pm/LauncherActivityInfo;->mActivityInfo:Landroid/content/pm/ActivityInfo; Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager; Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V +Landroid/content/pm/PackageItemInfo;->setForceSafeLabels(Z)V Landroid/content/pm/PackageManager;->buildRequestPermissionsIntent([Ljava/lang/String;)Landroid/content/Intent; Landroid/content/pm/PackageManager;->freeStorageAndNotify(JLandroid/content/pm/IPackageDataObserver;)V Landroid/content/pm/PackageManager;->freeStorageAndNotify(Ljava/lang/String;JLandroid/content/pm/IPackageDataObserver;)V @@ -443,6 +470,7 @@ Landroid/content/pm/PackageParser$ServiceIntentInfo;->service:Landroid/content/p Landroid/content/pm/PackageUserState;->()V Landroid/content/pm/ParceledListSlice;->(Ljava/util/List;)V Landroid/content/pm/ResolveInfo;->instantAppAvailable:Z +Landroid/content/pm/ShortcutManager;->mService:Landroid/content/pm/IShortcutService; Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey; Landroid/content/pm/UserInfo;->id:I Landroid/content/pm/UserInfo;->isPrimary()Z @@ -498,6 +526,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;->(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; @@ -514,6 +543,7 @@ Landroid/content/res/XmlBlock;->([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; @@ -552,6 +582,7 @@ Landroid/graphics/Bitmap;->reinit(IIZ)V Landroid/graphics/Camera;->native_instance:J Landroid/graphics/Canvas;->(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; @@ -587,6 +618,12 @@ Landroid/graphics/drawable/GradientDrawable$GradientState;->mThickness:I Landroid/graphics/drawable/GradientDrawable$GradientState;->mThicknessRatio:F Landroid/graphics/drawable/GradientDrawable$GradientState;->mWidth:I Landroid/graphics/drawable/GradientDrawable;->mPadding:Landroid/graphics/Rect; +Landroid/graphics/drawable/Icon;->getBitmap()Landroid/graphics/Bitmap; +Landroid/graphics/drawable/Icon;->getDataBytes()[B +Landroid/graphics/drawable/Icon;->getDataLength()I +Landroid/graphics/drawable/Icon;->getDataOffset()I +Landroid/graphics/drawable/Icon;->getResources()Landroid/content/res/Resources; +Landroid/graphics/drawable/Icon;->hasTint()Z Landroid/graphics/drawable/Icon;->mType:I Landroid/graphics/drawable/InsetDrawable;->mState:Landroid/graphics/drawable/InsetDrawable$InsetState; Landroid/graphics/drawable/NinePatchDrawable;->mNinePatchState:Landroid/graphics/drawable/NinePatchDrawable$NinePatchState; @@ -618,6 +655,8 @@ Landroid/graphics/Movie;->mNativeMovie:J Landroid/graphics/NinePatch$InsetStruct;->(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;->(JI)V Landroid/graphics/Region;->mNativeRegion:J Landroid/graphics/SurfaceTexture;->mFrameAvailableListener:J @@ -625,6 +664,7 @@ Landroid/graphics/SurfaceTexture;->mProducer:J Landroid/graphics/SurfaceTexture;->mSurfaceTexture:J Landroid/graphics/SurfaceTexture;->nativeDetachFromGLContext()I Landroid/graphics/SurfaceTexture;->postEventFromNative(Ljava/lang/ref/WeakReference;)V +Landroid/graphics/Typeface;->createFromFamiliesWithDefault([Landroid/graphics/FontFamily;II)Landroid/graphics/Typeface; Landroid/graphics/Typeface;->createFromFamiliesWithDefault([Landroid/graphics/FontFamily;Ljava/lang/String;II)Landroid/graphics/Typeface; Landroid/graphics/Typeface;->mStyle:I Landroid/graphics/Typeface;->sDefaults:[Landroid/graphics/Typeface; @@ -645,6 +685,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;->(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;->()V Landroid/hardware/SerialPort;->mNativeContext:I @@ -652,6 +694,7 @@ Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;->confidenceLevel:I Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;->(II)V Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;->userId:I Landroid/hardware/soundtrigger/SoundTrigger$GenericRecognitionEvent;->(IIZIIIZLandroid/media/AudioFormat;[B)V +Landroid/hardware/soundtrigger/SoundTrigger$GenericSoundModel;->(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;->(IIZIIIZLandroid/media/AudioFormat;[B[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V @@ -670,6 +713,7 @@ Landroid/hardware/soundtrigger/SoundTriggerModule;->postEventFromNative(Ljava/la Landroid/hardware/soundtrigger/SoundTrigger$ModuleProperties;->(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;->(ZZ[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;[B)V Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;->keyphrases:[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra; Landroid/hardware/soundtrigger/SoundTrigger$RecognitionEvent;->(IIZIIIZLandroid/media/AudioFormat;[B)V Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;->data:[B @@ -681,17 +725,37 @@ Landroid/hardware/SystemSensorManager$BaseEventQueue;->dispatchFlushCompleteEven Landroid/hardware/SystemSensorManager$BaseEventQueue;->dispatchSensorEvent(I[FIJ)V Landroid/hardware/usb/IUsbManager$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/hardware/usb/UsbDeviceConnection;->mNativeContext:J +Landroid/hardware/usb/UsbManager;->getPorts()[Landroid/hardware/usb/UsbPort; +Landroid/hardware/usb/UsbManager;->getPortStatus(Landroid/hardware/usb/UsbPort;)Landroid/hardware/usb/UsbPortStatus; 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;->()V Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V Landroid/icu/impl/number/DecimalFormatProperties;->writeObject(Ljava/io/ObjectOutputStream;)V Landroid/icu/impl/TimeZoneGenericNames;->readObject(Ljava/io/ObjectInputStream;)V +Landroid/icu/text/ArabicShaping;->isAlefMaksouraChar(C)Z +Landroid/icu/text/ArabicShaping;->isSeenTailFamilyChar(C)I +Landroid/icu/text/ArabicShaping;->isTailChar(C)Z +Landroid/icu/text/ArabicShaping;->isYehHamzaChar(C)Z Landroid/icu/text/DateFormat;->readObject(Ljava/io/ObjectInputStream;)V +Landroid/icu/text/DateFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale; Landroid/icu/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V +Landroid/icu/text/DateIntervalFormat;->()V Landroid/icu/text/DateIntervalFormat;->readObject(Ljava/io/ObjectInputStream;)V +Landroid/icu/text/DateTimePatternGenerator$DistanceInfo;->()V Landroid/icu/text/DecimalFormat_ICU58_Android;->readObject(Ljava/io/ObjectInputStream;)V Landroid/icu/text/DecimalFormat_ICU58_Android;->writeObject(Ljava/io/ObjectOutputStream;)V Landroid/icu/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V +Landroid/icu/text/DecimalFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale; Landroid/icu/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V Landroid/icu/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V Landroid/icu/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V @@ -703,13 +767,23 @@ Landroid/icu/text/PluralRules$FixedDecimal;->readObject(Ljava/io/ObjectInputStre Landroid/icu/text/PluralRules$FixedDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V Landroid/icu/text/PluralRules;->readObject(Ljava/io/ObjectInputStream;)V Landroid/icu/text/PluralRules;->writeObject(Ljava/io/ObjectOutputStream;)V +Landroid/icu/text/RuleBasedCollator;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale; Landroid/icu/text/RuleBasedNumberFormat;->readObject(Ljava/io/ObjectInputStream;)V Landroid/icu/text/RuleBasedNumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V Landroid/icu/text/SelectFormat;->readObject(Ljava/io/ObjectInputStream;)V Landroid/icu/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V Landroid/icu/text/SimpleDateFormat;->writeObject(Ljava/io/ObjectOutputStream;)V +Landroid/icu/text/SpoofChecker$ScriptSet;->and(I)V +Landroid/icu/text/SpoofChecker$ScriptSet;->()V +Landroid/icu/text/SpoofChecker$ScriptSet;->isFull()Z +Landroid/icu/text/SpoofChecker$ScriptSet;->setAll()V Landroid/icu/text/TimeZoneFormat;->readObject(Ljava/io/ObjectInputStream;)V Landroid/icu/text/TimeZoneFormat;->writeObject(Ljava/io/ObjectOutputStream;)V +Landroid/icu/text/TimeZoneNames$DefaultTimeZoneNames$FactoryImpl;->()V +Landroid/icu/text/Transliterator;->createFromRules(Ljava/lang/String;Ljava/lang/String;I)Landroid/icu/text/Transliterator; +Landroid/icu/text/Transliterator;->transliterate(Ljava/lang/String;)Ljava/lang/String; +Landroid/icu/text/UFormat;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale; +Landroid/icu/util/Calendar;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale; Landroid/icu/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V Landroid/icu/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V Landroid/icu/util/ChineseCalendar;->readObject(Ljava/io/ObjectInputStream;)V @@ -738,7 +812,11 @@ Landroid/media/AudioFormat;->(IIII)V Landroid/media/AudioFormat;->mChannelMask:I Landroid/media/AudioFormat;->mEncoding:I Landroid/media/AudioFormat;->mSampleRate:I +Landroid/media/audiofx/AudioEffect;->command(I[B[B)I +Landroid/media/audiofx/AudioEffect;->getParameter([I[B)I +Landroid/media/audiofx/AudioEffect;->getParameter([I[I)I Landroid/media/audiofx/AudioEffect;->(Ljava/util/UUID;Ljava/util/UUID;II)V +Landroid/media/audiofx/AudioEffect;->setParameter([I[S)I Landroid/media/AudioGainConfig;->(ILandroid/media/AudioGain;II[II)V Landroid/media/AudioGainConfig;->mChannelMask:I Landroid/media/AudioGainConfig;->mIndex:I @@ -753,6 +831,7 @@ Landroid/media/AudioManager;->getOutputLatency(I)I Landroid/media/AudioManager;->getService()Landroid/media/IAudioService; Landroid/media/AudioManager;->mAudioFocusIdListenerMap:Ljava/util/concurrent/ConcurrentHashMap; Landroid/media/AudioManager;->setMasterMute(ZI)V +Landroid/media/AudioManager;->startBluetoothScoVirtualCall()V Landroid/media/AudioManager;->STREAM_BLUETOOTH_SCO:I Landroid/media/AudioManager;->STREAM_SYSTEM_ENFORCED:I Landroid/media/AudioManager;->STREAM_TTS:I @@ -785,25 +864,36 @@ Landroid/media/AudioPort;->mActiveConfig:Landroid/media/AudioPortConfig; Landroid/media/AudioPort;->mGains:[Landroid/media/AudioGain; Landroid/media/AudioPort;->mHandle:Landroid/media/AudioHandle; Landroid/media/AudioPort;->mRole:I +Landroid/media/AudioRecordingConfiguration;->getClientPackageName()Ljava/lang/String; +Landroid/media/AudioRecordingConfiguration;->getClientUid()I Landroid/media/AudioRecord;->mNativeCallbackCookie:J Landroid/media/AudioRecord;->mNativeDeviceCallback:J Landroid/media/AudioRecord;->mNativeRecorderInJavaObj:J +Landroid/media/AudioRecord;->native_release()V Landroid/media/AudioRecord;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V Landroid/media/AudioSystem;->dynamicPolicyCallbackFromNative(ILjava/lang/String;I)V Landroid/media/AudioSystem;->errorCallbackFromNative(I)V Landroid/media/AudioSystem;->getPrimaryOutputFrameCount()I Landroid/media/AudioSystem;->getPrimaryOutputSamplingRate()I +Landroid/media/AudioSystem;->isStreamActive(II)Z Landroid/media/AudioSystem;->recordingCallbackFromNative(IIII[I)V Landroid/media/AudioSystem;->setDeviceConnectionState(IILjava/lang/String;Ljava/lang/String;)I +Landroid/media/AudioSystem;->setErrorCallback(Landroid/media/AudioSystem$ErrorCallback;)V +Landroid/media/AudioTrack;->deferred_connect(J)V Landroid/media/AudioTrack;->getLatency()I Landroid/media/AudioTrack;->mJniData:J Landroid/media/AudioTrack;->mNativeTrackInJavaObj:J Landroid/media/AudioTrack;->mStreamType:I +Landroid/media/AudioTrack;->native_release()V Landroid/media/AudioTrack;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V +Landroid/media/IAudioService;->getStreamMaxVolume(I)I +Landroid/media/IAudioService;->getStreamVolume(I)I +Landroid/media/IAudioService;->setStreamVolume(IIILjava/lang/String;)V Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService; Landroid/media/IAudioService$Stub$Proxy;->(Landroid/os/IBinder;)V Landroid/media/JetPlayer;->mNativePlayerInJavaObj:J Landroid/media/JetPlayer;->postEventFromNative(Ljava/lang/Object;III)V +Landroid/media/MediaCodec$CodecException;->(IILjava/lang/String;)V Landroid/media/MediaCodec;->releaseOutputBuffer(IZZJ)V Landroid/media/MediaFile;->FIRST_AUDIO_FILE_TYPE:I Landroid/media/MediaFile;->getFileType(Ljava/lang/String;)Landroid/media/MediaFile$MediaFileType; @@ -853,6 +943,11 @@ 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/session/MediaSession;->mCallback:Landroid/media/session/MediaSession$CallbackMessageHandler; +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; @@ -909,6 +1004,7 @@ Landroid/net/NetworkCapabilities;->getTransportTypes()[I Landroid/net/NetworkPolicyManager;->mService:Landroid/net/INetworkPolicyManager; Landroid/net/NetworkStats;->capacity:I Landroid/net/NetworkStats;->defaultNetwork:[I +Landroid/net/NetworkStatsHistory$Entry;->rxBytes:J Landroid/net/NetworkStats;->iface:[Ljava/lang/String; Landroid/net/NetworkStats;->metered:[I Landroid/net/NetworkStats;->operations:[J @@ -921,7 +1017,9 @@ Landroid/net/NetworkStats;->tag:[I Landroid/net/NetworkStats;->txBytes:[J Landroid/net/NetworkStats;->txPackets:[J Landroid/net/NetworkStats;->uid:[I +Landroid/net/NetworkTemplate;->buildTemplateWifi()Landroid/net/NetworkTemplate; Landroid/net/ProxyInfo;->(Ljava/lang/String;ILjava/lang/String;)V +Landroid/net/SntpClient;->()V Landroid/net/SSLCertificateSocketFactory;->castToOpenSSLSocket(Ljava/net/Socket;)Lcom/android/org/conscrypt/OpenSSLSocketImpl; Landroid/net/SSLCertificateSocketFactory;->getAlpnSelectedProtocol(Ljava/net/Socket;)[B Landroid/net/SSLCertificateSocketFactory;->getDelegate()Ljavax/net/ssl/SSLSocketFactory; @@ -963,18 +1061,36 @@ Landroid/net/wifi/ScanResult;->distanceCm:I Landroid/net/wifi/ScanResult;->distanceSdCm:I Landroid/net/wifi/ScanResult;->flags:J Landroid/net/wifi/ScanResult;->hessid:J +Landroid/net/wifi/ScanResult$InformationElement;->bytes:[B +Landroid/net/wifi/ScanResult$InformationElement;->EID_BSS_LOAD:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_ERP:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_EXTENDED_CAPS:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_EXTENDED_SUPPORTED_RATES:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_HT_OPERATION:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_INTERWORKING:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_ROAMING_CONSORTIUM:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_RSN:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_SSID:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_SUPPORTED_RATES:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_TIM:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_VHT_OPERATION:I +Landroid/net/wifi/ScanResult$InformationElement;->EID_VSA:I +Landroid/net/wifi/ScanResult$InformationElement;->id:I +Landroid/net/wifi/ScanResult;->informationElements:[Landroid/net/wifi/ScanResult$InformationElement; Landroid/net/wifi/ScanResult;->numUsage:I Landroid/net/wifi/ScanResult;->seen:J Landroid/net/wifi/ScanResult;->untrusted:Z Landroid/net/wifi/ScanResult;->wifiSsid:Landroid/net/wifi/WifiSsid; Landroid/net/wifi/WifiConfiguration;->apBand:I Landroid/net/wifi/WifiConfiguration;->apChannel:I +Landroid/net/wifi/WifiConfiguration;->defaultGwMacAddress:Ljava/lang/String; Landroid/net/wifi/WifiConfiguration;->mIpConfiguration:Landroid/net/IpConfiguration; Landroid/net/wifi/WifiConfiguration;->validatedInternetAccess:Z Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/String; Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String; Landroid/net/wifi/WifiInfo;->getMeteredHint()Z Landroid/net/wifi/WifiInfo;->mMacAddress:Ljava/lang/String; +Landroid/net/wifi/WifiInfo;->removeDoubleQuotes(Ljava/lang/String;)Ljava/lang/String; Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V Landroid/net/wifi/WifiManager;->connect(ILandroid/net/wifi/WifiManager$ActionListener;)V Landroid/net/wifi/WifiManager;->forget(ILandroid/net/wifi/WifiManager$ActionListener;)V @@ -996,6 +1112,7 @@ Landroid/os/AsyncTask;->setDefaultExecutor(Ljava/util/concurrent/Executor;)V Landroid/os/BatteryStats;->getUidStats()Landroid/util/SparseArray; Landroid/os/BatteryStats$HistoryItem;->states2:I Landroid/os/BatteryStats;->NUM_DATA_CONNECTION_TYPES:I +Landroid/os/BatteryStats;->startIteratingHistoryLocked()Z Landroid/os/BatteryStats$Timer;->getTotalTimeLocked(JI)J Landroid/os/BatteryStats$Uid;->getFullWifiLockTime(JI)J Landroid/os/BatteryStats$Uid;->getProcessStats()Landroid/util/ArrayMap; @@ -1046,6 +1163,7 @@ Landroid/os/Debug$MemoryInfo;->otherSwappablePss:I Landroid/os/Debug$MemoryInfo;->otherSwappedOut:I Landroid/os/Debug$MemoryInfo;->otherSwappedOutPss:I Landroid/os/Environment;->buildExternalStorageAppDataDirs(Ljava/lang/String;)[Ljava/io/File; +Landroid/os/Environment;->getVendorDirectory()Ljava/io/File; Landroid/os/FileObserver$ObserverThread;->onEvent(IILjava/lang/String;)V Landroid/os/FileUtils;->checksumCrc32(Ljava/io/File;)J Landroid/os/FileUtils;->copyFile(Ljava/io/File;Ljava/io/File;)Z @@ -1059,6 +1177,7 @@ Landroid/os/FileUtils;->stringToFile(Ljava/io/File;Ljava/lang/String;)V Landroid/os/FileUtils;->stringToFile(Ljava/lang/String;Ljava/lang/String;)V Landroid/os/Handler;->getIMessenger()Landroid/os/IMessenger; Landroid/os/Handler;->hasCallbacks(Ljava/lang/Runnable;)Z +Landroid/os/Handler;->(Z)V Landroid/os/Handler;->mCallback:Landroid/os/Handler$Callback; Landroid/os/Handler;->mMessenger:Landroid/os/IMessenger; Landroid/os/HwParcel;->(Z)V @@ -1092,7 +1211,10 @@ Landroid/os/Message;->target:Landroid/os/Handler; Landroid/os/Message;->when:J Landroid/os/ParcelFileDescriptor;->(Ljava/io/FileDescriptor;)V Landroid/os/Parcel;->mNativePtr:J +Landroid/os/Parcel;->readArrayMap(Landroid/util/ArrayMap;Ljava/lang/ClassLoader;)V Landroid/os/Parcel$ReadWriteHelper;->()V +Landroid/os/Parcel;->writeArrayMap(Landroid/util/ArrayMap;)V +Landroid/os/PowerManager;->getDefaultScreenBrightnessSetting()I Landroid/os/PowerManager;->getMaximumScreenBrightnessSetting()I Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I Landroid/os/PowerManager;->isLightDeviceIdleMode()Z @@ -1119,6 +1241,7 @@ Landroid/os/ServiceManager;->listServices()[Ljava/lang/String; Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/IServiceManager; Landroid/os/ServiceManager;->sCache:Ljava/util/HashMap; Landroid/os/ServiceManager;->sServiceManager:Landroid/os/IServiceManager; +Landroid/os/SharedMemory;->getFd()I Landroid/os/storage/DiskInfo;->getDescription()Ljava/lang/String; Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager; Landroid/os/storage/IStorageManager$Stub$Proxy;->(Landroid/os/IBinder;)V @@ -1169,34 +1292,68 @@ Landroid/os/UpdateLock;->NOW_IS_CONVENIENT:Ljava/lang/String; Landroid/os/UpdateLock;->release()V Landroid/os/UpdateLock;->TIMESTAMP:Ljava/lang/String; Landroid/os/UpdateLock;->UPDATE_LOCK_CHANGED:Ljava/lang/String; +Landroid/os/UserHandle;->AID_APP_END:I +Landroid/os/UserHandle;->AID_APP_START:I +Landroid/os/UserHandle;->AID_CACHE_GID_START:I +Landroid/os/UserHandle;->AID_ROOT:I +Landroid/os/UserHandle;->AID_SHARED_GID_START:I Landroid/os/UserHandle;->ALL:Landroid/os/UserHandle; +Landroid/os/UserHandle;->CURRENT:Landroid/os/UserHandle; +Landroid/os/UserHandle;->CURRENT_OR_SELF:Landroid/os/UserHandle; +Landroid/os/UserHandle;->ERR_GID:I Landroid/os/UserHandle;->getAppIdFromSharedAppGid(I)I Landroid/os/UserHandle;->getCallingUserId()I Landroid/os/UserHandle;->getUid(II)I Landroid/os/UserHandle;->getUserId(I)I Landroid/os/UserHandle;->(I)V +Landroid/os/UserHandle;->MU_ENABLED:Z +Landroid/os/UserHandle;->OWNER:Landroid/os/UserHandle; Landroid/os/UserHandle;->PER_USER_RANGE:I +Landroid/os/UserHandle;->SYSTEM:Landroid/os/UserHandle; +Landroid/os/UserHandle;->USER_ALL:I +Landroid/os/UserHandle;->USER_CURRENT:I +Landroid/os/UserHandle;->USER_CURRENT_OR_SELF:I +Landroid/os/UserHandle;->USER_NULL:I Landroid/os/UserHandle;->USER_OWNER:I +Landroid/os/UserHandle;->USER_SERIAL_SYSTEM:I +Landroid/os/UserHandle;->USER_SYSTEM:I Landroid/os/UserManager;->getBadgedLabelForUser(Ljava/lang/CharSequence;Landroid/os/UserHandle;)Ljava/lang/CharSequence; Landroid/os/UserManager;->get(Landroid/content/Context;)Landroid/os/UserManager; Landroid/os/UserManager;->getMaxSupportedUsers()I Landroid/os/UserManager;->getProfiles(I)Ljava/util/List; Landroid/os/UserManager;->getUserHandle()I Landroid/os/UserManager;->getUserHandle(I)I +Landroid/os/UserManager;->getUserIcon(I)Landroid/graphics/Bitmap; Landroid/os/UserManager;->getUserInfo(I)Landroid/content/pm/UserInfo; Landroid/os/UserManager;->getUserSerialNumber(I)I Landroid/os/UserManager;->getUsers()Ljava/util/List; +Landroid/os/UserManager;->getUserStartRealtime()J +Landroid/os/UserManager;->getUserUnlockRealtime()J Landroid/os/UserManager;->hasBaseUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z Landroid/os/UserManager;->isLinkedUser()Z Landroid/os/UserManager;->isUserUnlocked(I)Z +Landroid/os/VintfObject;->getHalNamesAndVersions()[Ljava/lang/String; +Landroid/os/VintfObject;->getSepolicyVersion()Ljava/lang/String; +Landroid/os/VintfObject;->getTargetFrameworkCompatibilityMatrixVersion()Ljava/lang/Long; +Landroid/os/VintfObject;->getVndkSnapshots()Ljava/util/Map; Landroid/os/VintfObject;->report()[Ljava/lang/String; +Landroid/os/VintfRuntimeInfo;->getCpuInfo()Ljava/lang/String; +Landroid/os/VintfRuntimeInfo;->getHardwareId()Ljava/lang/String; +Landroid/os/VintfRuntimeInfo;->getKernelVersion()Ljava/lang/String; +Landroid/os/VintfRuntimeInfo;->getNodeName()Ljava/lang/String; +Landroid/os/VintfRuntimeInfo;->getOsName()Ljava/lang/String; +Landroid/os/VintfRuntimeInfo;->getOsRelease()Ljava/lang/String; +Landroid/os/VintfRuntimeInfo;->getOsVersion()Ljava/lang/String; Landroid/os/WorkSource;->add(ILjava/lang/String;)Z Landroid/os/WorkSource;->add(I)Z +Landroid/os/WorkSource;->addReturningNewbs(Landroid/os/WorkSource;)Landroid/os/WorkSource; Landroid/os/WorkSource;->get(I)I Landroid/os/WorkSource;->getName(I)Ljava/lang/String; +Landroid/os/WorkSource;->(I)V Landroid/os/WorkSource;->mNames:[Ljava/lang/String; Landroid/os/WorkSource;->mNum:I Landroid/os/WorkSource;->mUids:[I +Landroid/os/WorkSource;->setReturningDiffs(Landroid/os/WorkSource;)[Landroid/os/WorkSource; Landroid/os/WorkSource;->size()I Landroid/preference/DialogPreference;->mBuilder:Landroid/app/AlertDialog$Builder; Landroid/preference/DialogPreference;->mDialogIcon:Landroid/graphics/drawable/Drawable; @@ -1241,10 +1398,14 @@ Landroid/provider/Browser;->clearSearches(Landroid/content/ContentResolver;)V Landroid/provider/Browser;->deleteFromHistory(Landroid/content/ContentResolver;Ljava/lang/String;)V Landroid/provider/Browser;->getVisitedHistory(Landroid/content/ContentResolver;)[Ljava/lang/String; Landroid/provider/Browser;->sendString(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V +Landroid/provider/CalendarContract$CalendarAlerts;->findNextAlarmTime(Landroid/content/ContentResolver;J)J +Landroid/provider/CalendarContract$CalendarAlerts;->rescheduleMissedAlarms(Landroid/content/ContentResolver;Landroid/content/Context;Landroid/app/AlarmManager;)V Landroid/provider/Settings$ContentProviderHolder;->mContentProvider:Landroid/content/IContentProvider; Landroid/provider/Settings$Global;->ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED:Ljava/lang/String; Landroid/provider/Settings$Global;->PACKAGE_VERIFIER_ENABLE:Ljava/lang/String; Landroid/provider/Settings$Global;->sNameValueCache:Landroid/provider/Settings$NameValueCache; +Landroid/provider/Settings;->isCallingPackageAllowedToDrawOverlays(Landroid/content/Context;ILjava/lang/String;Z)Z +Landroid/provider/Settings;->isCallingPackageAllowedToWriteSettings(Landroid/content/Context;ILjava/lang/String;Z)Z Landroid/provider/Settings$NameValueCache;->mProviderHolder:Landroid/provider/Settings$ContentProviderHolder; Landroid/provider/Settings$Secure;->ACCESSIBILITY_AUTOCLICK_ENABLED:Ljava/lang/String; Landroid/provider/Settings$Secure;->ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:Ljava/lang/String; @@ -1259,6 +1420,7 @@ Landroid/provider/Settings$System;->getStringForUser(Landroid/content/ContentRes Landroid/provider/Settings$System;->HEARING_AID:Ljava/lang/String; Landroid/provider/Settings$System;->MASTER_MONO:Ljava/lang/String; Landroid/provider/Settings$System;->putStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;I)Z +Landroid/provider/Settings$System;->SCREEN_AUTO_BRIGHTNESS_ADJ:Ljava/lang/String; Landroid/provider/Settings$System;->sNameValueCache:Landroid/provider/Settings$NameValueCache; Landroid/provider/Telephony$Sms;->addMessageToUri(ILandroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZZJ)Landroid/net/Uri; Landroid/provider/Telephony$Sms;->addMessageToUri(ILandroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZZ)Landroid/net/Uri; @@ -1509,10 +1671,65 @@ 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; Landroid/system/Int32Ref;->value:I +Landroid/system/OsConstants;->AF_NETLINK:I +Landroid/system/OsConstants;->AF_PACKET:I +Landroid/system/OsConstants;->ARPHRD_ETHER:I +Landroid/system/OsConstants;->ARPHRD_LOOPBACK:I +Landroid/system/OsConstants;->CAP_TO_INDEX(I)I +Landroid/system/OsConstants;->CAP_TO_MASK(I)I +Landroid/system/OsConstants;->ENONET:I +Landroid/system/OsConstants;->ETH_P_ALL:I +Landroid/system/OsConstants;->ETH_P_ARP:I +Landroid/system/OsConstants;->ETH_P_IP:I +Landroid/system/OsConstants;->ETH_P_IPV6:I +Landroid/system/OsConstants;->EUSERS:I +Landroid/system/OsConstants;->ICMP6_ECHO_REPLY:I +Landroid/system/OsConstants;->ICMP6_ECHO_REQUEST:I +Landroid/system/OsConstants;->ICMP_ECHO:I +Landroid/system/OsConstants;->ICMP_ECHOREPLY:I +Landroid/system/OsConstants;->initConstants()V +Landroid/system/OsConstants;->()V +Landroid/system/OsConstants;->IP_MULTICAST_ALL:I +Landroid/system/OsConstants;->IP_RECVTOS:I +Landroid/system/OsConstants;->_LINUX_CAPABILITY_VERSION_3:I +Landroid/system/OsConstants;->MAP_POPULATE:I +Landroid/system/OsConstants;->NETLINK_NETFILTER:I +Landroid/system/OsConstants;->NETLINK_ROUTE:I +Landroid/system/OsConstants;->O_DIRECT:I +Landroid/system/OsConstants;->placeholder()I +Landroid/system/OsConstants;->PR_CAP_AMBIENT:I +Landroid/system/OsConstants;->PR_CAP_AMBIENT_RAISE:I +Landroid/system/OsConstants;->RLIMIT_NOFILE:I +Landroid/system/OsConstants;->RTMGRP_IPV4_IFADDR:I +Landroid/system/OsConstants;->RTMGRP_IPV4_MROUTE:I +Landroid/system/OsConstants;->RTMGRP_IPV4_ROUTE:I +Landroid/system/OsConstants;->RTMGRP_IPV4_RULE:I +Landroid/system/OsConstants;->RTMGRP_IPV6_IFADDR:I +Landroid/system/OsConstants;->RTMGRP_IPV6_IFINFO:I +Landroid/system/OsConstants;->RTMGRP_IPV6_MROUTE:I +Landroid/system/OsConstants;->RTMGRP_IPV6_PREFIX:I +Landroid/system/OsConstants;->RTMGRP_IPV6_ROUTE:I +Landroid/system/OsConstants;->RTMGRP_LINK:I +Landroid/system/OsConstants;->RTMGRP_NEIGH:I +Landroid/system/OsConstants;->RTMGRP_NOTIFY:I +Landroid/system/OsConstants;->RTMGRP_TC:I +Landroid/system/OsConstants;->SO_DOMAIN:I +Landroid/system/OsConstants;->SO_PROTOCOL:I +Landroid/system/OsConstants;->SPLICE_F_MORE:I +Landroid/system/OsConstants;->SPLICE_F_MOVE:I +Landroid/system/OsConstants;->SPLICE_F_NONBLOCK:I +Landroid/system/OsConstants;->TIOCOUTQ:I +Landroid/system/OsConstants;->UDP_ENCAP_ESPINUDP:I +Landroid/system/OsConstants;->UDP_ENCAP_ESPINUDP_NON_IKE:I +Landroid/system/OsConstants;->UDP_ENCAP:I +Landroid/system/OsConstants;->UNIX_PATH_MAX:I +Landroid/system/OsConstants;->XATTR_CREATE:I +Landroid/system/OsConstants;->XATTR_REPLACE:I Landroid/system/StructTimeval;->fromMillis(J)Landroid/system/StructTimeval; Landroid/telecom/TelecomManager;->EXTRA_IS_HANDOVER:Ljava/lang/String; Landroid/telecom/TelecomManager;->getUserSelectedOutgoingPhoneAccount()Landroid/telecom/PhoneAccountHandle; @@ -1524,6 +1741,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 @@ -1534,6 +1752,7 @@ Landroid/telephony/SignalStrength;->getLteRsrp()I Landroid/telephony/SignalStrength;->getLteRsrq()I Landroid/telephony/SignalStrength;->getLteRssnr()I Landroid/telephony/SignalStrength;->getLteSignalStrength()I +Landroid/telephony/SignalStrength;->()V Landroid/telephony/SignalStrength;->mGsmBitErrorRate:I Landroid/telephony/SignalStrength;->mGsmSignalStrength:I Landroid/telephony/SignalStrength;->mLteCqi:I @@ -1548,10 +1767,12 @@ 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; Landroid/telephony/SubscriptionManager;->getDefaultSmsPhoneId()I +Landroid/telephony/SubscriptionManager;->getDefaultVoiceSubscriptionInfo()Landroid/telephony/SubscriptionInfo; Landroid/telephony/SubscriptionManager;->getPhoneId(I)I Landroid/telephony/SubscriptionManager;->getSlotIndex(I)I Landroid/telephony/SubscriptionManager;->getSubId(I)[I @@ -1652,6 +1873,7 @@ Landroid/text/TextPaint;->setUnderlineText(IF)V Landroid/transition/ChangeBounds;->BOTTOM_RIGHT_ONLY_PROPERTY:Landroid/util/Property; Landroid/transition/ChangeBounds;->POSITION_PROPERTY:Landroid/util/Property; Landroid/transition/TransitionManager;->sRunningTransitions:Ljava/lang/ThreadLocal; +Landroid/util/ArrayMap;->append(Ljava/lang/Object;Ljava/lang/Object;)V Landroid/util/ArrayMap;->mBaseCacheSize:I Landroid/util/ArrayMap;->mTwiceBaseCacheSize:I Landroid/util/DisplayMetrics;->noncompatHeightPixels:I @@ -1666,7 +1888,11 @@ 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;->(I)V +Landroid/util/Rational;->mDenominator:I +Landroid/util/Rational;->mNumerator:I Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V Landroid/util/Singleton;->mInstance:Ljava/lang/Object; Landroid/util/SparseIntArray;->mKeys:[I @@ -1716,6 +1942,7 @@ Landroid/view/InputChannel;->mPtr:J Landroid/view/InputDevice;->addMotionRange(IIFFFFF)V Landroid/view/InputDevice;->(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 @@ -1834,6 +2061,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 @@ -1844,7 +2072,9 @@ Landroid/view/View;->dispatchAttachedToWindow(Landroid/view/View$AttachInfo;I)V Landroid/view/View;->dispatchDetachedFromWindow()V Landroid/view/View;->fitsSystemWindows()Z Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate; +Landroid/view/View;->getInverseMatrix()Landroid/graphics/Matrix; Landroid/view/View;->getListenerInfo()Landroid/view/View$ListenerInfo; +Landroid/view/View;->getLocationOnScreen()[I Landroid/view/View;->getTransitionAlpha()F Landroid/view/View;->getViewRootImpl()Landroid/view/ViewRootImpl; Landroid/view/ViewGroup;->dispatchViewAdded(Landroid/view/View;)V @@ -2002,6 +2232,7 @@ Landroid/widget/ActivityChooserModel;->get(Landroid/content/Context;Ljava/lang/S Landroid/widget/ActivityChooserView;->setExpandActivityOverflowButtonDrawable(Landroid/graphics/drawable/Drawable;)V Landroid/widget/AdapterView;->mDataChanged:Z Landroid/widget/AdapterView;->mFirstPosition:I +Landroid/widget/AdapterView;->mOldSelectedPosition:I Landroid/widget/AdapterView;->setNextSelectedPositionInt(I)V Landroid/widget/AdapterView;->setSelectedPositionInt(I)V Landroid/widget/AutoCompleteTextView;->doAfterTextChanged()V @@ -2014,6 +2245,7 @@ Landroid/widget/DatePicker;->mDelegate:Landroid/widget/DatePicker$DatePickerDele Landroid/widget/EdgeEffect;->mPaint:Landroid/graphics/Paint; Landroid/widget/Editor;->invalidateTextDisplayList()V Landroid/widget/Editor;->mShowCursor:J +Landroid/widget/Editor;->mShowSoftInputOnFocus:Z Landroid/widget/ExpandableListView;->mChildDivider:Landroid/graphics/drawable/Drawable; Landroid/widget/FastScroller;->mContainerRect:Landroid/graphics/Rect; Landroid/widget/FastScroller;->mHeaderCount:I @@ -2162,12 +2394,82 @@ Landroid/widget/VideoView;->mSHCallback:Landroid/view/SurfaceHolder$Callback; Landroid/widget/VideoView;->mUri:Landroid/net/Uri; Landroid/widget/VideoView;->mVideoHeight:I Landroid/widget/VideoView;->mVideoWidth:I +Lcom/android/ims/internal/uce/common/CapInfo;->()V +Lcom/android/ims/internal/uce/common/CapInfo;->setCapTimestamp(J)V +Lcom/android/ims/internal/uce/common/CapInfo;->setCdViaPresenceSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setExts([Ljava/lang/String;)V +Lcom/android/ims/internal/uce/common/CapInfo;->setFtHttpSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setFtSnFSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setFtSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setFtThumbSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setFullSnFGroupChatSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPullFtSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPullSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPushSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setImSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setIpVideoSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setIpVoiceSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setIsSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVideoCallSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVideoOnlyCallSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVoiceCallSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setSmSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setSpSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setVsDuringCSSupported(Z)V +Lcom/android/ims/internal/uce/common/CapInfo;->setVsSupported(Z)V +Lcom/android/ims/internal/uce/common/StatusCode;->()V +Lcom/android/ims/internal/uce/common/StatusCode;->setStatusCode(I)V +Lcom/android/ims/internal/uce/common/UceLong;->getUceLong()J +Lcom/android/ims/internal/uce/common/UceLong;->setUceLong(J)V +Lcom/android/ims/internal/uce/presence/PresCmdId;->()V +Lcom/android/ims/internal/uce/presence/PresCmdId;->setCmdId(I)V +Lcom/android/ims/internal/uce/presence/PresCmdStatus;->()V +Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setCmdId(Lcom/android/ims/internal/uce/presence/PresCmdId;)V +Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setRequestId(I)V +Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setStatus(Lcom/android/ims/internal/uce/common/StatusCode;)V +Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setUserData(I)V +Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;->()V +Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;->setPublishTrigeerType(I)V +Lcom/android/ims/internal/uce/presence/PresResInfo;->()V +Lcom/android/ims/internal/uce/presence/PresResInfo;->setDisplayName(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/presence/PresResInfo;->setInstanceInfo(Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;)V +Lcom/android/ims/internal/uce/presence/PresResInfo;->setResUri(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->()V +Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setPresentityUri(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setReason(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setResId(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setResInstanceState(I)V +Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setTupleInfo([Lcom/android/ims/internal/uce/presence/PresTupleInfo;)V +Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->()V +Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setFullState(Z)V +Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setListName(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setPresSubscriptionState(Lcom/android/ims/internal/uce/presence/PresSubscriptionState;)V +Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setRequestId(I)V +Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setSubscriptionExpireTime(I)V +Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setSubscriptionTerminatedReason(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setUri(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setVersion(I)V +Lcom/android/ims/internal/uce/presence/PresSipResponse;->()V +Lcom/android/ims/internal/uce/presence/PresSipResponse;->setCmdId(Lcom/android/ims/internal/uce/presence/PresCmdId;)V +Lcom/android/ims/internal/uce/presence/PresSipResponse;->setReasonPhrase(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/presence/PresSipResponse;->setRequestId(I)V +Lcom/android/ims/internal/uce/presence/PresSipResponse;->setRetryAfter(I)V +Lcom/android/ims/internal/uce/presence/PresSipResponse;->setSipResponseCode(I)V +Lcom/android/ims/internal/uce/presence/PresSubscriptionState;->()V +Lcom/android/ims/internal/uce/presence/PresSubscriptionState;->setPresSubscriptionState(I)V +Lcom/android/ims/internal/uce/presence/PresTupleInfo;->()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/ims/internal/uce/uceservice/IUceListener$Stub;->()V +Lcom/android/internal/app/AlertController$RecycleListView;->(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;->(Landroid/os/IBinder;)V Lcom/android/internal/app/IBatteryStats;->getStatistics()[B Lcom/android/internal/app/IBatteryStats$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IBatteryStats; Lcom/android/internal/app/IBatteryStats$Stub$Proxy;->(Landroid/os/IBinder;)V +Lcom/android/internal/app/IVoiceInteractionManagerService;->getKeyphraseSoundModel(ILjava/lang/String;)Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseSoundModel; Lcom/android/internal/app/IVoiceInteractionManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IVoiceInteractionManagerService; Lcom/android/internal/app/IVoiceInteractionManagerService$Stub$Proxy;->showSessionFromSession(Landroid/os/IBinder;Landroid/os/Bundle;I)Z Lcom/android/internal/location/ILocationProvider$Stub;->()V @@ -2366,6 +2668,7 @@ Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->(Landroid/os/IBinder;)V Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;->(Landroid/os/IBinder;)V +Lcom/android/internal/util/FastPrintWriter;->(Ljava/io/OutputStream;)V Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap; Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager; Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;->getEnabledInputMethodList()Ljava/util/List; @@ -2381,7 +2684,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; @@ -2389,6 +2698,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; @@ -2431,6 +2748,7 @@ Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setSoWriteTimeout(I)V Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mContext:J Lcom/android/org/conscrypt/TrustManagerImpl;->(Ljava/security/KeyStore;)V +Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String; Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList; Ldalvik/system/BlockGuard;->getThreadPolicy()Ldalvik/system/BlockGuard$Policy; @@ -2440,9 +2758,11 @@ Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard; Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V Ldalvik/system/CloseGuard;->warnIfOpen()V Ldalvik/system/DexFile;->getClassNameList(Ljava/lang/Object;)[Ljava/lang/String; +Ldalvik/system/DexFile;->isBackedByOatFile()Z Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class; Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object; Ldalvik/system/DexFile;->mFileName:Ljava/lang/String; +Ldalvik/system/DexFile;->mInternalCookie:Ljava/lang/Object; Ldalvik/system/DexFile;->openDexFile(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ljava/lang/Object; Ldalvik/system/DexPathList;->addDexPath(Ljava/lang/String;Ljava/io/File;)V Ldalvik/system/DexPathList;->dexElements:[Ldalvik/system/DexPathList$Element; @@ -2560,6 +2880,7 @@ Ljava/lang/Thread;->priority:I Ljava/lang/Throwable;->backtrace:Ljava/lang/Object; Ljava/lang/Throwable;->cause:Ljava/lang/Throwable; Ljava/lang/Throwable;->detailMessage:Ljava/lang/String; +Ljava/lang/Throwable;->nativeFillInStackTrace()Ljava/lang/Object; Ljava/lang/Throwable;->readObject(Ljava/io/ObjectInputStream;)V Ljava/lang/Throwable;->stackTrace:[Ljava/lang/StackTraceElement; Ljava/lang/Throwable;->suppressedExceptions:Ljava/util/List; @@ -2629,6 +2950,7 @@ Ljava/security/spec/ECParameterSpec;->getCurveName()Ljava/lang/String; Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V Ljava/security/Timestamp;->readObject(Ljava/io/ObjectInputStream;)V Ljava/text/ChoiceFormat;->readObject(Ljava/io/ObjectInputStream;)V +Ljava/text/DateFormat;->is24Hour:Ljava/lang/Boolean; Ljava/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V Ljava/text/DateFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V Ljava/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V @@ -2651,11 +2973,13 @@ Ljava/time/chrono/MinguoDate;->readObject(Ljava/io/ObjectInputStream;)V Ljava/time/chrono/ThaiBuddhistChronology;->readObject(Ljava/io/ObjectInputStream;)V Ljava/time/chrono/ThaiBuddhistDate;->readObject(Ljava/io/ObjectInputStream;)V Ljava/time/Duration;->readObject(Ljava/io/ObjectInputStream;)V +Ljava/time/Duration;->toSeconds()Ljava/math/BigDecimal; Ljava/time/Instant;->readObject(Ljava/io/ObjectInputStream;)V Ljava/time/LocalDate;->readObject(Ljava/io/ObjectInputStream;)V Ljava/time/LocalDateTime;->readObject(Ljava/io/ObjectInputStream;)V Ljava/time/LocalTime;->readObject(Ljava/io/ObjectInputStream;)V Ljava/time/MonthDay;->readObject(Ljava/io/ObjectInputStream;)V +Ljava/time/OffsetDateTime;->(Ljava/time/LocalDateTime;Ljava/time/ZoneOffset;)V Ljava/time/OffsetDateTime;->readObject(Ljava/io/ObjectInputStream;)V Ljava/time/OffsetTime;->readObject(Ljava/io/ObjectInputStream;)V Ljava/time/Period;->readObject(Ljava/io/ObjectInputStream;)V @@ -2762,6 +3086,7 @@ Ljava/util/prefs/PreferenceChangeEvent;->writeObject(Ljava/io/ObjectOutputStream Ljava/util/PriorityQueue;->readObject(Ljava/io/ObjectInputStream;)V Ljava/util/PriorityQueue;->writeObject(Ljava/io/ObjectOutputStream;)V Ljava/util/Random;->readObject(Ljava/io/ObjectInputStream;)V +Ljava/util/Random;->seedUniquifier()J Ljava/util/Random;->writeObject(Ljava/io/ObjectOutputStream;)V Ljava/util/regex/Matcher;->appendPos:I Ljava/util/regex/Pattern;->readObject(Ljava/io/ObjectInputStream;)V diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt new file mode 100644 index 0000000000000000000000000000000000000000..952b28b8b820fbb2ab7ac37703b0972539e0e666 --- /dev/null +++ b/config/hiddenapi-vendor-list.txt @@ -0,0 +1,552 @@ +Landroid/app/ActivityManager$RecentTaskInfo;->configuration:Landroid/content/res/Configuration; +Landroid/app/ActivityManager$TaskDescription;->loadTaskDescriptionIcon(Ljava/lang/String;I)Landroid/graphics/Bitmap; +Landroid/app/ActivityManager$TaskSnapshot;->getSnapshot()Landroid/graphics/GraphicBuffer; +Landroid/app/ActivityOptions;->makeRemoteAnimation(Landroid/view/RemoteAnimationAdapter;)Landroid/app/ActivityOptions; +Landroid/app/ActivityOptions;->setSplitScreenCreateMode(I)V +Landroid/app/Activity;->registerRemoteAnimations(Landroid/view/RemoteAnimationDefinition;)V +Landroid/app/IActivityController$Stub;->()V +Landroid/app/IActivityManager;->cancelRecentsAnimation()V +Landroid/app/IActivityManager;->cancelTaskWindowTransition(I)V +Landroid/app/IActivityManager;->closeSystemDialogs(Ljava/lang/String;)V +Landroid/app/IActivityManager;->getCurrentUser()Landroid/content/pm/UserInfo; +Landroid/app/IActivityManager;->getFilteredTasks(III)Ljava/util/List; +Landroid/app/IActivityManager;->getLockTaskModeState()I +Landroid/app/IActivityManager;->getRecentTasks(III)Landroid/content/pm/ParceledListSlice; +Landroid/app/IActivityManager;->getTaskSnapshot(IZ)Landroid/app/ActivityManager$TaskSnapshot; +Landroid/app/IActivityManager;->registerTaskStackListener(Landroid/app/ITaskStackListener;)V +Landroid/app/IActivityManager;->removeTask(I)Z +Landroid/app/IActivityManager;->startActivityFromRecents(ILandroid/os/Bundle;)I +Landroid/app/IActivityManager;->startRecentsActivity(Landroid/content/Intent;Landroid/app/IAssistDataReceiver;Landroid/view/IRecentsAnimationRunner;)V +Landroid/app/IAssistDataReceiver;->onHandleAssistData(Landroid/os/Bundle;)V +Landroid/app/IAssistDataReceiver;->onHandleAssistScreenshot(Landroid/graphics/Bitmap;)V +Landroid/app/IAssistDataReceiver$Stub;->()V +Landroid/app/KeyguardManager;->isDeviceLocked(I)Z +Landroid/app/StatusBarManager;->removeIcon(Ljava/lang/String;)V +Landroid/app/StatusBarManager;->setIcon(Ljava/lang/String;IILjava/lang/String;)V +Landroid/app/TaskStackListener;->onActivityDismissingDockedStack()V +Landroid/app/TaskStackListener;->onActivityForcedResizable(Ljava/lang/String;II)V +Landroid/app/TaskStackListener;->onActivityLaunchOnSecondaryDisplayFailed()V +Landroid/app/TaskStackListener;->onActivityPinned(Ljava/lang/String;III)V +Landroid/app/TaskStackListener;->onActivityRequestedOrientationChanged(II)V +Landroid/app/TaskStackListener;->onActivityUnpinned()V +Landroid/app/TaskStackListener;->onPinnedActivityRestartAttempt(Z)V +Landroid/app/TaskStackListener;->onPinnedStackAnimationEnded()V +Landroid/app/TaskStackListener;->onPinnedStackAnimationStarted()V +Landroid/app/TaskStackListener;->onTaskMovedToFront(I)V +Landroid/app/TaskStackListener;->onTaskProfileLocked(II)V +Landroid/app/TaskStackListener;->onTaskRemoved(I)V +Landroid/app/TaskStackListener;->onTaskSnapshotChanged(ILandroid/app/ActivityManager$TaskSnapshot;)V +Landroid/app/TaskStackListener;->onTaskStackChanged()V +Landroid/app/VrStateCallback;->()V +Landroid/app/VrStateCallback;->onPersistentVrStateChanged(Z)V +Landroid/app/WallpaperColors;->(Landroid/graphics/Color;Landroid/graphics/Color;Landroid/graphics/Color;I)V +Landroid/companion/AssociationRequest;->getDeviceFilters()Ljava/util/List; +Landroid/companion/AssociationRequest;->isSingleDevice()Z +Landroid/companion/BluetoothDeviceFilter;->getAddress()Ljava/lang/String; +Landroid/companion/BluetoothDeviceFilterUtils;->getDeviceDisplayNameInternal(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String; +Landroid/companion/BluetoothDeviceFilterUtils;->getDeviceDisplayNameInternal(Landroid/net/wifi/ScanResult;)Ljava/lang/String; +Landroid/companion/BluetoothDeviceFilterUtils;->getDeviceMacAddress(Landroid/os/Parcelable;)Ljava/lang/String; +Landroid/companion/BluetoothLeDeviceFilter;->getScanFilter()Landroid/bluetooth/le/ScanFilter; +Landroid/companion/DeviceFilter;->getDeviceDisplayName(Landroid/os/Parcelable;)Ljava/lang/String; +Landroid/companion/DeviceFilter;->matches(Landroid/os/Parcelable;)Z +Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelected(Ljava/lang/String;ILjava/lang/String;)V +Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelectionCancel()V +Landroid/companion/ICompanionDeviceDiscoveryService$Stub;->()V +Landroid/companion/IFindDeviceCallback;->onSuccess(Landroid/app/PendingIntent;)V +Landroid/content/Context;->getOpPackageName()Ljava/lang/String; +Landroid/content/Context;->registerReceiverAsUser(Landroid/content/BroadcastReceiver;Landroid/os/UserHandle;Landroid/content/IntentFilter;Ljava/lang/String;Landroid/os/Handler;)Landroid/content/Intent; +Landroid/content/Context;->startActivityAsUser(Landroid/content/Intent;Landroid/os/UserHandle;)V +Landroid/content/Context;->startServiceAsUser(Landroid/content/Intent;Landroid/os/UserHandle;)Landroid/content/ComponentName; +Landroid/content/ContextWrapper;->getThemeResId()I +Landroid/content/pm/IPackageDataObserver;->onRemoveCompleted(Ljava/lang/String;Z)V +Landroid/content/pm/IPackageDataObserver$Stub;->()V +Landroid/content/pm/IPackageDeleteObserver;->packageDeleted(Ljava/lang/String;I)V +Landroid/content/pm/IPackageDeleteObserver$Stub;->()V +Landroid/content/pm/IPackageManager;->getActivityInfo(Landroid/content/ComponentName;II)Landroid/content/pm/ActivityInfo; +Landroid/content/pm/IPackageManager;->getHomeActivities(Ljava/util/List;)Landroid/content/ComponentName; +Landroid/content/pm/IPackageStatsObserver;->onGetStatsCompleted(Landroid/content/pm/PackageStats;Z)V +Landroid/database/sqlite/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri; +Landroid/graphics/AvoidXfermode;->(IILandroid/graphics/AvoidXfermode$Mode;)V +Landroid/graphics/Bitmap;->createGraphicBufferHandle()Landroid/graphics/GraphicBuffer; +Landroid/graphics/Bitmap;->createHardwareBitmap(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap; +Landroid/graphics/Canvas;->clipRegion(Landroid/graphics/Region;Landroid/graphics/Region$Op;)Z +Landroid/graphics/Canvas;->clipRegion(Landroid/graphics/Region;)Z +Landroid/graphics/drawable/Drawable;->isProjected()Z +Landroid/graphics/drawable/Drawable;->updateTintFilter(Landroid/graphics/PorterDuffColorFilter;Landroid/content/res/ColorStateList;Landroid/graphics/PorterDuff$Mode;)Landroid/graphics/PorterDuffColorFilter; +Landroid/hardware/camera2/CaptureRequest$Key;->(Ljava/lang/String;Ljava/lang/Class;)V +Landroid/hardware/location/GeofenceHardware;->(Landroid/hardware/location/IGeofenceHardware;)V +Landroid/hardware/location/IActivityRecognitionHardwareClient;->onAvailabilityChanged(ZLandroid/hardware/location/IActivityRecognitionHardware;)V +Landroid/location/IFusedProvider;->onFusedLocationHardwareChange(Landroid/hardware/location/IFusedLocationHardware;)V +Landroid/location/IGeocodeProvider;->getFromLocation(DDILandroid/location/GeocoderParams;Ljava/util/List;)Ljava/lang/String; +Landroid/location/IGeocodeProvider;->getFromLocationName(Ljava/lang/String;DDDDILandroid/location/GeocoderParams;Ljava/util/List;)Ljava/lang/String; +Landroid/location/IGeofenceProvider;->setGeofenceHardware(Landroid/hardware/location/IGeofenceHardware;)V +Landroid/location/ILocationManager;->reportLocation(Landroid/location/Location;Z)V +Landroid/media/AudioManager;->registerAudioPortUpdateListener(Landroid/media/AudioManager$OnAudioPortUpdateListener;)V +Landroid/media/AudioManager;->unregisterAudioPortUpdateListener(Landroid/media/AudioManager$OnAudioPortUpdateListener;)V +Landroid/media/AudioSystem;->checkAudioFlinger()I +Landroid/media/AudioSystem;->getParameters(Ljava/lang/String;)Ljava/lang/String; +Landroid/media/AudioSystem;->setParameters(Ljava/lang/String;)I +Landroid/media/MediaDrm$Certificate;->getContent()[B +Landroid/media/MediaDrm$Certificate;->getWrappedPrivateKey()[B +Landroid/media/MediaDrm$CertificateRequest;->getData()[B +Landroid/media/MediaDrm$CertificateRequest;->getDefaultUrl()Ljava/lang/String; +Landroid/media/MediaDrm;->getCertificateRequest(ILjava/lang/String;)Landroid/media/MediaDrm$CertificateRequest; +Landroid/media/MediaDrm;->provideCertificateResponse([B)Landroid/media/MediaDrm$Certificate; +Landroid/media/MediaDrm;->signRSA([BLjava/lang/String;[B[B)[B +Landroid/media/tv/ITvRemoteProvider$Stub;->()V +Landroid/media/tv/ITvRemoteServiceInput;->clearInputBridge(Landroid/os/IBinder;)V +Landroid/media/tv/ITvRemoteServiceInput;->closeInputBridge(Landroid/os/IBinder;)V +Landroid/media/tv/ITvRemoteServiceInput;->openInputBridge(Landroid/os/IBinder;Ljava/lang/String;III)V +Landroid/media/tv/ITvRemoteServiceInput;->sendKeyDown(Landroid/os/IBinder;I)V +Landroid/media/tv/ITvRemoteServiceInput;->sendKeyUp(Landroid/os/IBinder;I)V +Landroid/media/tv/ITvRemoteServiceInput;->sendPointerDown(Landroid/os/IBinder;III)V +Landroid/media/tv/ITvRemoteServiceInput;->sendPointerSync(Landroid/os/IBinder;)V +Landroid/media/tv/ITvRemoteServiceInput;->sendPointerUp(Landroid/os/IBinder;I)V +Landroid/media/tv/ITvRemoteServiceInput;->sendTimestamp(Landroid/os/IBinder;J)V +Landroid/net/ConnectivityManager$PacketKeepaliveCallback;->()V +Landroid/net/ConnectivityManager$PacketKeepaliveCallback;->onError(I)V +Landroid/net/ConnectivityManager$PacketKeepaliveCallback;->onStarted()V +Landroid/net/ConnectivityManager$PacketKeepaliveCallback;->onStopped()V +Landroid/net/ConnectivityManager$PacketKeepalive;->stop()V +Landroid/net/ConnectivityManager;->startNattKeepalive(Landroid/net/Network;ILandroid/net/ConnectivityManager$PacketKeepaliveCallback;Ljava/net/InetAddress;ILjava/net/InetAddress;)Landroid/net/ConnectivityManager$PacketKeepalive; +Landroid/net/ConnectivityManager;->startUsingNetworkFeature(ILjava/lang/String;)I +Landroid/net/ConnectivityManager;->stopUsingNetworkFeature(ILjava/lang/String;)I +Landroid/net/DhcpResults;->(Landroid/net/DhcpResults;)V +Landroid/net/DhcpResults;->(Landroid/net/StaticIpConfiguration;)V +Landroid/net/DhcpResults;->()V +Landroid/net/DhcpResults;->leaseDuration:I +Landroid/net/DhcpResults;->mtu:I +Landroid/net/DhcpResults;->serverAddress:Ljava/net/Inet4Address; +Landroid/net/DhcpResults;->vendorInfo:Ljava/lang/String; +Landroid/net/IConnectivityManager;->getAllNetworkState()[Landroid/net/NetworkState; +Landroid/net/INetd;->interfaceAddAddress(Ljava/lang/String;Ljava/lang/String;I)V +Landroid/net/INetd$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetd; +Landroid/net/INetworkPolicyManager;->getNetworkQuotaInfo(Landroid/net/NetworkState;)Landroid/net/NetworkQuotaInfo; +Landroid/net/INetworkPolicyManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkPolicyManager; +Landroid/net/INetworkStatsService;->openSession()Landroid/net/INetworkStatsSession; +Landroid/net/INetworkStatsService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkStatsService; +Landroid/net/INetworkStatsSession;->getHistoryForNetwork(Landroid/net/NetworkTemplate;I)Landroid/net/NetworkStatsHistory; +Landroid/net/INetworkStatsSession;->getHistoryForUid(Landroid/net/NetworkTemplate;IIII)Landroid/net/NetworkStatsHistory; +Landroid/net/InterfaceConfiguration;->()V +Landroid/net/InterfaceConfiguration;->setLinkAddress(Landroid/net/LinkAddress;)V +Landroid/net/LinkAddress;->(Ljava/lang/String;)V +Landroid/net/LinkAddress;->(Ljava/net/InetAddress;I)V +Landroid/net/LinkAddress;->isIPv6()Z +Landroid/net/LinkAddress;->isSameAddressAs(Landroid/net/LinkAddress;)Z +Landroid/net/LinkProperties;->addDnsServer(Ljava/net/InetAddress;)Z +Landroid/net/LinkProperties;->addRoute(Landroid/net/RouteInfo;)Z +Landroid/net/LinkProperties;->addStackedLink(Landroid/net/LinkProperties;)Z +Landroid/net/LinkProperties;->clear()V +Landroid/net/LinkProperties;->compareProvisioning(Landroid/net/LinkProperties;Landroid/net/LinkProperties;)Landroid/net/LinkProperties$ProvisioningChange; +Landroid/net/LinkProperties;->getMtu()I +Landroid/net/LinkProperties;->getStackedLinks()Ljava/util/List; +Landroid/net/LinkProperties;->hasGlobalIPv6Address()Z +Landroid/net/LinkProperties;->hasIPv4Address()Z +Landroid/net/LinkProperties;->hasIPv4DefaultRoute()Z +Landroid/net/LinkProperties;->hasIPv4DnsServer()Z +Landroid/net/LinkProperties;->hasIPv6DefaultRoute()Z +Landroid/net/LinkProperties;->hasIPv6DnsServer()Z +Landroid/net/LinkProperties;->(Landroid/net/LinkProperties;)V +Landroid/net/LinkProperties;->()V +Landroid/net/LinkProperties;->isIdenticalAddresses(Landroid/net/LinkProperties;)Z +Landroid/net/LinkProperties;->isIdenticalDnses(Landroid/net/LinkProperties;)Z +Landroid/net/LinkProperties;->isIdenticalRoutes(Landroid/net/LinkProperties;)Z +Landroid/net/LinkProperties;->isIdenticalStackedLinks(Landroid/net/LinkProperties;)Z +Landroid/net/LinkProperties;->isIPv6Provisioned()Z +Landroid/net/LinkProperties;->isProvisioned()Z +Landroid/net/LinkProperties;->isReachable(Ljava/net/InetAddress;)Z +Landroid/net/LinkProperties$ProvisioningChange;->GAINED_PROVISIONING:Landroid/net/LinkProperties$ProvisioningChange; +Landroid/net/LinkProperties$ProvisioningChange;->LOST_PROVISIONING:Landroid/net/LinkProperties$ProvisioningChange; +Landroid/net/LinkProperties$ProvisioningChange;->STILL_NOT_PROVISIONED:Landroid/net/LinkProperties$ProvisioningChange; +Landroid/net/LinkProperties$ProvisioningChange;->STILL_PROVISIONED:Landroid/net/LinkProperties$ProvisioningChange; +Landroid/net/LinkProperties$ProvisioningChange;->values()[Landroid/net/LinkProperties$ProvisioningChange; +Landroid/net/LinkProperties;->removeDnsServer(Ljava/net/InetAddress;)Z +Landroid/net/LinkProperties;->removeRoute(Landroid/net/RouteInfo;)Z +Landroid/net/LinkProperties;->setDnsServers(Ljava/util/Collection;)V +Landroid/net/LinkProperties;->setDomains(Ljava/lang/String;)V +Landroid/net/LinkProperties;->setInterfaceName(Ljava/lang/String;)V +Landroid/net/LinkProperties;->setLinkAddresses(Ljava/util/Collection;)V +Landroid/net/LinkProperties;->setMtu(I)V +Landroid/net/LinkProperties;->setTcpBufferSizes(Ljava/lang/String;)V +Landroid/net/MacAddress;->ALL_ZEROS_ADDRESS:Landroid/net/MacAddress; +Landroid/net/metrics/ApfProgramEvent;->actualLifetime:J +Landroid/net/metrics/ApfProgramEvent;->currentRas:I +Landroid/net/metrics/ApfProgramEvent;->filteredRas:I +Landroid/net/metrics/ApfProgramEvent;->flagsFor(ZZ)I +Landroid/net/metrics/ApfProgramEvent;->flags:I +Landroid/net/metrics/ApfProgramEvent;->()V +Landroid/net/metrics/ApfProgramEvent;->lifetime:J +Landroid/net/metrics/ApfProgramEvent;->programLength:I +Landroid/net/metrics/ApfStats;->droppedRas:I +Landroid/net/metrics/ApfStats;->durationMs:J +Landroid/net/metrics/ApfStats;->()V +Landroid/net/metrics/ApfStats;->matchingRas:I +Landroid/net/metrics/ApfStats;->maxProgramSize:I +Landroid/net/metrics/ApfStats;->parseErrors:I +Landroid/net/metrics/ApfStats;->programUpdatesAll:I +Landroid/net/metrics/ApfStats;->programUpdatesAllowingMulticast:I +Landroid/net/metrics/ApfStats;->programUpdates:I +Landroid/net/metrics/ApfStats;->receivedRas:I +Landroid/net/metrics/ApfStats;->zeroLifetimeRas:I +Landroid/net/metrics/DhcpClientEvent;->(Ljava/lang/String;I)V +Landroid/net/metrics/DhcpErrorEvent;->BOOTP_TOO_SHORT:I +Landroid/net/metrics/DhcpErrorEvent;->BUFFER_UNDERFLOW:I +Landroid/net/metrics/DhcpErrorEvent;->DHCP_BAD_MAGIC_COOKIE:I +Landroid/net/metrics/DhcpErrorEvent;->DHCP_INVALID_OPTION_LENGTH:I +Landroid/net/metrics/DhcpErrorEvent;->DHCP_NO_COOKIE:I +Landroid/net/metrics/DhcpErrorEvent;->DHCP_NO_MSG_TYPE:I +Landroid/net/metrics/DhcpErrorEvent;->DHCP_UNKNOWN_MSG_TYPE:I +Landroid/net/metrics/DhcpErrorEvent;->errorCodeWithOption(II)I +Landroid/net/metrics/DhcpErrorEvent;->(I)V +Landroid/net/metrics/DhcpErrorEvent;->L2_TOO_SHORT:I +Landroid/net/metrics/DhcpErrorEvent;->L2_WRONG_ETH_TYPE:I +Landroid/net/metrics/DhcpErrorEvent;->L3_INVALID_IP:I +Landroid/net/metrics/DhcpErrorEvent;->L3_NOT_IPV4:I +Landroid/net/metrics/DhcpErrorEvent;->L3_TOO_SHORT:I +Landroid/net/metrics/DhcpErrorEvent;->L4_NOT_UDP:I +Landroid/net/metrics/DhcpErrorEvent;->L4_WRONG_PORT:I +Landroid/net/metrics/DhcpErrorEvent;->PARSING_ERROR:I +Landroid/net/metrics/DhcpErrorEvent;->RECEIVE_ERROR:I +Landroid/net/metrics/IpConnectivityLog;->()V +Landroid/net/metrics/IpConnectivityLog;->log(Landroid/os/Parcelable;)Z +Landroid/net/metrics/IpConnectivityLog;->log(Ljava/lang/String;Landroid/os/Parcelable;)Z +Landroid/net/metrics/IpManagerEvent;->(IJ)V +Landroid/net/metrics/IpReachabilityEvent;->(I)V +Landroid/net/metrics/IpReachabilityEvent;->nudFailureEventType(ZZ)I +Landroid/net/metrics/RaEvent$Builder;->build()Landroid/net/metrics/RaEvent; +Landroid/net/metrics/RaEvent$Builder;->()V +Landroid/net/metrics/RaEvent$Builder;->updateDnsslLifetime(J)Landroid/net/metrics/RaEvent$Builder; +Landroid/net/metrics/RaEvent$Builder;->updatePrefixPreferredLifetime(J)Landroid/net/metrics/RaEvent$Builder; +Landroid/net/metrics/RaEvent$Builder;->updatePrefixValidLifetime(J)Landroid/net/metrics/RaEvent$Builder; +Landroid/net/metrics/RaEvent$Builder;->updateRdnssLifetime(J)Landroid/net/metrics/RaEvent$Builder; +Landroid/net/metrics/RaEvent$Builder;->updateRouteInfoLifetime(J)Landroid/net/metrics/RaEvent$Builder; +Landroid/net/metrics/RaEvent$Builder;->updateRouterLifetime(J)Landroid/net/metrics/RaEvent$Builder; +Landroid/net/NetworkCapabilities;->getNetworkSpecifier()Landroid/net/NetworkSpecifier; +Landroid/net/NetworkCapabilities;->getSignalStrength()I +Landroid/net/NetworkCapabilities;->hasSignalStrength()Z +Landroid/net/NetworkCapabilities;->transportNamesOf([I)Ljava/lang/String; +Landroid/net/Network;->(I)V +Landroid/net/NetworkQuotaInfo;->getEstimatedBytes()J +Landroid/net/NetworkQuotaInfo;->getHardLimitBytes()J +Landroid/net/NetworkQuotaInfo;->getSoftLimitBytes()J +Landroid/net/NetworkRequest$Builder;->setSignalStrength(I)Landroid/net/NetworkRequest$Builder; +Landroid/net/NetworkStats;->combineValues(Landroid/net/NetworkStats$Entry;)Landroid/net/NetworkStats; +Landroid/net/NetworkStats$Entry;->()V +Landroid/net/NetworkStatsHistory$Entry;->txBytes:J +Landroid/net/NetworkStatsHistory;->getStart()J +Landroid/net/NetworkStatsHistory;->getValues(JJLandroid/net/NetworkStatsHistory$Entry;)Landroid/net/NetworkStatsHistory$Entry; +Landroid/net/NetworkStats;->(JI)V +Landroid/net/NetworkTemplate;->buildTemplateMobileAll(Ljava/lang/String;)Landroid/net/NetworkTemplate; +Landroid/net/NetworkUtils;->attachControlPacketFilter(Ljava/io/FileDescriptor;I)V +Landroid/net/NetworkUtils;->attachDhcpFilter(Ljava/io/FileDescriptor;)V +Landroid/net/NetworkUtils;->attachRaFilter(Ljava/io/FileDescriptor;I)V +Landroid/net/NetworkUtils;->getImplicitNetmask(Ljava/net/Inet4Address;)I +Landroid/net/NetworkUtils;->netmaskToPrefixLength(Ljava/net/Inet4Address;)I +Landroid/net/NetworkUtils;->protectFromVpn(Ljava/io/FileDescriptor;)Z +Landroid/net/RouteInfo;->hasGateway()Z +Landroid/net/RouteInfo;->(Landroid/net/IpPrefix;Ljava/net/InetAddress;Ljava/lang/String;)V +Landroid/net/SntpClient;->getNtpTime()J +Landroid/net/SntpClient;->requestTime(Ljava/lang/String;I)Z +Landroid/net/StaticIpConfiguration;->dnsServers:Ljava/util/ArrayList; +Landroid/net/StaticIpConfiguration;->domains:Ljava/lang/String; +Landroid/net/StaticIpConfiguration;->gateway:Ljava/net/InetAddress; +Landroid/net/StaticIpConfiguration;->getRoutes(Ljava/lang/String;)Ljava/util/List; +Landroid/net/StaticIpConfiguration;->ipAddress:Landroid/net/LinkAddress; +Landroid/net/StringNetworkSpecifier;->specifier:Ljava/lang/String; +Landroid/net/TrafficStats;->getMobileTcpRxPackets()J +Landroid/net/TrafficStats;->getMobileTcpTxPackets()J +Landroid/net/wifi/WifiInfo;->is5GHz()Z +Landroid/net/wifi/WifiInfo;->score:I +Landroid/os/AsyncResult;->exception:Ljava/lang/Throwable; +Landroid/os/AsyncResult;->forMessage(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)Landroid/os/AsyncResult; +Landroid/os/AsyncResult;->(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Throwable;)V +Landroid/os/AsyncResult;->result:Ljava/lang/Object; +Landroid/os/AsyncResult;->userObj:Ljava/lang/Object; +Landroid/os/BatteryStats;->getNextHistoryLocked(Landroid/os/BatteryStats$HistoryItem;)Z +Landroid/os/BatteryStats$HistoryItem;->batteryLevel:B +Landroid/os/BatteryStats$HistoryItem;->cmd:B +Landroid/os/BatteryStats$HistoryItem;->()V +Landroid/os/BatteryStats$HistoryItem;->states:I +Landroid/os/BatteryStats$HistoryItem;->time:J +Landroid/os/BatteryStats$Uid;->getWifiRunningTime(JI)J +Landroid/os/BatteryStats$Uid;->()V +Landroid/os/BatteryStats$Uid$Wakelock;->getWakeTime(I)Landroid/os/BatteryStats$Timer; +Landroid/os/Handler;->getMain()Landroid/os/Handler; +Landroid/os/Handler;->(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V +Landroid/os/HwBinder;->reportSyspropChanged()V +Landroid/os/INetworkManagementService;->clearInterfaceAddresses(Ljava/lang/String;)V +Landroid/os/INetworkManagementService;->disableIpv6(Ljava/lang/String;)V +Landroid/os/INetworkManagementService;->enableIpv6(Ljava/lang/String;)V +Landroid/os/INetworkManagementService;->registerObserver(Landroid/net/INetworkManagementEventObserver;)V +Landroid/os/INetworkManagementService;->setInterfaceConfig(Ljava/lang/String;Landroid/net/InterfaceConfiguration;)V +Landroid/os/INetworkManagementService;->setInterfaceIpv6PrivacyExtensions(Ljava/lang/String;Z)V +Landroid/os/INetworkManagementService;->setIPv6AddrGenMode(Ljava/lang/String;I)V +Landroid/os/INetworkManagementService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/INetworkManagementService; +Landroid/os/INetworkManagementService;->unregisterObserver(Landroid/net/INetworkManagementEventObserver;)V +Landroid/os/IPowerManager;->reboot(ZLjava/lang/String;Z)V +Landroid/os/IRemoteCallback$Stub;->()V +Landroid/os/Message;->setCallback(Ljava/lang/Runnable;)Landroid/os/Message; +Landroid/os/Parcel;->readBlob()[B +Landroid/os/Parcel;->readStringArray()[Ljava/lang/String; +Landroid/os/Parcel;->writeBlob([B)V +Landroid/os/PowerManager;->isScreenBrightnessBoosted()Z +Landroid/os/Registrant;->clear()V +Landroid/os/Registrant;->(Landroid/os/Handler;ILjava/lang/Object;)V +Landroid/os/RegistrantList;->add(Landroid/os/Registrant;)V +Landroid/os/RegistrantList;->addUnique(Landroid/os/Handler;ILjava/lang/Object;)V +Landroid/os/RegistrantList;->()V +Landroid/os/RegistrantList;->notifyRegistrants(Landroid/os/AsyncResult;)V +Landroid/os/RegistrantList;->notifyRegistrants()V +Landroid/os/RegistrantList;->removeCleared()V +Landroid/os/RegistrantList;->remove(Landroid/os/Handler;)V +Landroid/os/Registrant;->notifyRegistrant(Landroid/os/AsyncResult;)V +Landroid/os/Registrant;->notifyRegistrant()V +Landroid/os/RemoteException;->rethrowFromSystemServer()Ljava/lang/RuntimeException; +Landroid/os/ServiceSpecificException;->errorCode:I +Landroid/os/SystemProperties;->reportSyspropChanged()V +Landroid/print/PrintDocumentAdapter$LayoutResultCallback;->()V +Landroid/print/PrintDocumentAdapter$WriteResultCallback;->()V +Landroid/provider/CalendarContract$Events;->PROVIDER_WRITABLE_COLUMNS:[Ljava/lang/String; +Landroid/service/vr/VrListenerService;->onCurrentVrActivityChanged(Landroid/content/ComponentName;ZI)V +Landroid/system/NetlinkSocketAddress;->(II)V +Landroid/system/Os;->bind(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V +Landroid/system/Os;->connect(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V +Landroid/system/Os;->sendto(Ljava/io/FileDescriptor;[BIIILjava/net/SocketAddress;)I +Landroid/system/Os;->setsockoptIfreq(Ljava/io/FileDescriptor;IILjava/lang/String;)V +Landroid/system/Os;->setsockoptTimeval(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V +Landroid/system/PacketSocketAddress;->(I[B)V +Landroid/system/PacketSocketAddress;->(SI)V +Landroid/telecom/TelecomManager;->from(Landroid/content/Context;)Landroid/telecom/TelecomManager; +Landroid/telecom/VideoProfile$CameraCapabilities;->(IIZF)V +Landroid/telephony/ims/compat/feature/MMTelFeature;->()V +Landroid/telephony/ims/compat/ImsService;->()V +Landroid/telephony/ims/compat/stub/ImsCallSessionImplBase;->()V +Landroid/telephony/ims/compat/stub/ImsConfigImplBase;->(Landroid/content/Context;)V +Landroid/telephony/ims/compat/stub/ImsUtListenerImplBase;->()V +Landroid/telephony/ims/ImsCallForwardInfo;->()V +Landroid/telephony/ims/ImsCallProfile;->presentationToOIR(I)I +Landroid/telephony/ims/ImsExternalCallState;->(ILandroid/net/Uri;ZIIZ)V +Landroid/telephony/ims/ImsReasonInfo;->(IILjava/lang/String;)V +Landroid/telephony/ims/ImsReasonInfo;->(II)V +Landroid/telephony/ims/ImsStreamMediaProfile;->()V +Landroid/telephony/PhoneNumberUtils;->isEmergencyNumber(ILjava/lang/String;)Z +Landroid/telephony/PhoneNumberUtils;->isPotentialEmergencyNumber(ILjava/lang/String;)Z +Landroid/telephony/PhoneNumberUtils;->isPotentialLocalEmergencyNumber(Landroid/content/Context;ILjava/lang/String;)Z +Landroid/telephony/PhoneStateListener;->(Ljava/lang/Integer;Landroid/os/Looper;)V +Landroid/telephony/PhoneStateListener;->(Ljava/lang/Integer;)V +Landroid/telephony/PreciseCallState;->getBackgroundCallState()I +Landroid/telephony/PreciseCallState;->getForegroundCallState()I +Landroid/telephony/RadioAccessFamily;->getRafFromNetworkType(I)I +Landroid/telephony/RadioAccessFamily;->(II)V +Landroid/telephony/Rlog;->d(Ljava/lang/String;Ljava/lang/String;)I +Landroid/telephony/Rlog;->e(Ljava/lang/String;Ljava/lang/String;)I +Landroid/telephony/Rlog;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I +Landroid/telephony/Rlog;->i(Ljava/lang/String;Ljava/lang/String;)I +Landroid/telephony/ServiceState;->getDataRoaming()Z +Landroid/telephony/ServiceState;->getRilDataRadioTechnology()I +Landroid/telephony/ServiceState;->getVoiceRegState()I +Landroid/telephony/ServiceState;->isCdma(I)Z +Landroid/telephony/ServiceState;->isEmergencyOnly()Z +Landroid/telephony/ServiceState;->mergeServiceStates(Landroid/telephony/ServiceState;Landroid/telephony/ServiceState;)Landroid/telephony/ServiceState; +Landroid/telephony/SubscriptionManager;->getResourcesForSubId(Landroid/content/Context;I)Landroid/content/res/Resources; +Landroid/telephony/SubscriptionManager;->isActiveSubId(I)Z +Landroid/telephony/SubscriptionManager;->isUsableSubIdValue(I)Z +Landroid/telephony/SubscriptionManager;->isValidPhoneId(I)Z +Landroid/telephony/SubscriptionManager;->isValidSlotIndex(I)Z +Landroid/telephony/SubscriptionManager;->isValidSubscriptionId(I)Z +Landroid/telephony/SubscriptionManager;->putPhoneIdAndSubIdExtra(Landroid/content/Intent;II)V +Landroid/telephony/TelephonyManager;->getIntAtIndex(Landroid/content/ContentResolver;Ljava/lang/String;I)I +Landroid/telephony/TelephonyManager;->getVoiceNetworkType(I)I +Landroid/telephony/TelephonyManager;->putIntAtIndex(Landroid/content/ContentResolver;Ljava/lang/String;II)Z +Landroid/util/FloatMath;->ceil(F)F +Landroid/util/FloatMath;->cos(F)F +Landroid/util/FloatMath;->exp(F)F +Landroid/util/FloatMath;->floor(F)F +Landroid/util/FloatMath;->sin(F)F +Landroid/util/FloatMath;->sqrt(F)F +Landroid/util/IconDrawableFactory;->getBadgedIcon(Landroid/content/pm/PackageItemInfo;Landroid/content/pm/ApplicationInfo;I)Landroid/graphics/drawable/Drawable; +Landroid/util/IconDrawableFactory;->newInstance(Landroid/content/Context;)Landroid/util/IconDrawableFactory; +Landroid/util/LocalLog;->(I)V +Landroid/util/LocalLog;->log(Ljava/lang/String;)V +Landroid/util/LocalLog$ReadOnlyLocalLog;->dump(Ljava/io/FileDescriptor;Ljava/io/PrintWriter;[Ljava/lang/String;)V +Landroid/util/LocalLog;->readOnlyLocalLog()Landroid/util/LocalLog$ReadOnlyLocalLog; +Landroid/util/LongArray;->add(IJ)V +Landroid/util/LongArray;->get(I)J +Landroid/util/LongArray;->()V +Landroid/util/LongArray;->size()I +Landroid/util/Slog;->wtf(Ljava/lang/String;Ljava/lang/String;)I +Landroid/view/AppTransitionAnimationSpec;->(ILandroid/graphics/GraphicBuffer;Landroid/graphics/Rect;)V +Landroid/view/BatchedInputEventReceiver;->(Landroid/view/InputChannel;Landroid/os/Looper;Landroid/view/Choreographer;)V +Landroid/view/Choreographer;->getSfInstance()Landroid/view/Choreographer; +Landroid/view/DisplayListCanvas;->drawRenderNode(Landroid/view/RenderNode;)V +Landroid/view/IAppTransitionAnimationSpecsFuture$Stub;->()V +Landroid/view/InputEventReceiver;->onInputEvent(Landroid/view/InputEvent;I)V +Landroid/view/IRecentsAnimationController;->finish(Z)V +Landroid/view/IRecentsAnimationController;->screenshotTask(I)Landroid/app/ActivityManager$TaskSnapshot; +Landroid/view/IRecentsAnimationController;->setInputConsumerEnabled(Z)V +Landroid/view/IRecentsAnimationRunner;->onAnimationCanceled()V +Landroid/view/IRecentsAnimationRunner;->onAnimationStart(Landroid/view/IRecentsAnimationController;[Landroid/view/RemoteAnimationTarget;)V +Landroid/view/IRecentsAnimationRunner;->onAnimationStart_New(Landroid/view/IRecentsAnimationController;[Landroid/view/RemoteAnimationTarget;Landroid/graphics/Rect;Landroid/graphics/Rect;)V +Landroid/view/IRecentsAnimationRunner$Stub;->()V +Landroid/view/IRemoteAnimationFinishedCallback;->onAnimationFinished()V +Landroid/view/IRemoteAnimationRunner;->onAnimationCancelled()V +Landroid/view/IRemoteAnimationRunner;->onAnimationStart([Landroid/view/RemoteAnimationTarget;Landroid/view/IRemoteAnimationFinishedCallback;)V +Landroid/view/IRemoteAnimationRunner$Stub;->()V +Landroid/view/IWindowManager;->createInputConsumer(Landroid/os/IBinder;Ljava/lang/String;Landroid/view/InputChannel;)V +Landroid/view/IWindowManager;->destroyInputConsumer(Ljava/lang/String;)Z +Landroid/view/IWindowManager;->endProlongedAnimations()V +Landroid/view/IWindowManager;->getStableInsets(ILandroid/graphics/Rect;)V +Landroid/view/IWindowManager;->overridePendingAppTransitionMultiThumbFuture(Landroid/view/IAppTransitionAnimationSpecsFuture;Landroid/os/IRemoteCallback;Z)V +Landroid/view/IWindowManager;->overridePendingAppTransitionRemote(Landroid/view/RemoteAnimationAdapter;)V +Landroid/view/IWindowManager;->setNavBarVirtualKeyHapticFeedbackEnabled(Z)V +Landroid/view/RemoteAnimationAdapter;->(Landroid/view/IRemoteAnimationRunner;JJ)V +Landroid/view/RemoteAnimationDefinition;->addRemoteAnimation(ILandroid/view/RemoteAnimationAdapter;)V +Landroid/view/RemoteAnimationDefinition;->()V +Landroid/view/RenderNode;->create(Ljava/lang/String;Landroid/view/View;)Landroid/view/RenderNode; +Landroid/view/RenderNode;->end(Landroid/view/DisplayListCanvas;)V +Landroid/view/RenderNode;->isValid()Z +Landroid/view/RenderNode;->setClipToBounds(Z)Z +Landroid/view/RenderNode;->setLeftTopRightBottom(IIII)Z +Landroid/view/RenderNode;->start(II)Landroid/view/DisplayListCanvas; +Landroid/view/SurfaceControl$Transaction;->apply()V +Landroid/view/SurfaceControl$Transaction;->deferTransactionUntil(Landroid/view/SurfaceControl;Landroid/os/IBinder;J)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->deferTransactionUntilSurface(Landroid/view/SurfaceControl;Landroid/view/Surface;J)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->hide(Landroid/view/SurfaceControl;)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->()V +Landroid/view/SurfaceControl$Transaction;->setAlpha(Landroid/view/SurfaceControl;F)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->setColor(Landroid/view/SurfaceControl;[F)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->setFinalCrop(Landroid/view/SurfaceControl;Landroid/graphics/Rect;)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->setLayer(Landroid/view/SurfaceControl;I)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->setMatrix(Landroid/view/SurfaceControl;FFFF)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->setMatrix(Landroid/view/SurfaceControl;Landroid/graphics/Matrix;[F)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->setPosition(Landroid/view/SurfaceControl;FF)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->setSize(Landroid/view/SurfaceControl;II)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->setWindowCrop(Landroid/view/SurfaceControl;Landroid/graphics/Rect;)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl$Transaction;->show(Landroid/view/SurfaceControl;)Landroid/view/SurfaceControl$Transaction; +Landroid/view/Surface;->getNextFrameNumber()J +Landroid/view/ThreadedRenderer;->createHardwareBitmap(Landroid/view/RenderNode;II)Landroid/graphics/Bitmap; +Landroid/view/View;->hideTooltip()V +Landroid/view/View;->setTooltip(Ljava/lang/CharSequence;)V +Landroid/webkit/WebSettings;->getPluginsPath()Ljava/lang/String; +Landroid/webkit/WebSettings;->getUseDoubleTree()Z +Landroid/webkit/WebSettings;->setPluginsPath(Ljava/lang/String;)V +Landroid/webkit/WebSettings;->setUseDoubleTree(Z)V +Landroid/webkit/WebView;->getPluginList()Landroid/webkit/PluginList; +Landroid/webkit/WebView;->getZoomControls()Landroid/view/View; +Landroid/webkit/WebView;->refreshPlugins(Z)V +Landroid/widget/ListView;->lookForSelectablePosition(IZ)I +Lcom/android/ims/ImsConfigListener;->onSetFeatureResponse(IIII)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionConferenceStateUpdated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsConferenceState;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHandoverFailed(Lcom/android/ims/internal/IImsCallSession;IILandroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHandover(Lcom/android/ims/internal/IImsCallSession;IILandroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHeld(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHoldFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHoldReceived(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionInviteParticipantsRequestDelivered(Lcom/android/ims/internal/IImsCallSession;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionInviteParticipantsRequestFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMergeComplete(Lcom/android/ims/internal/IImsCallSession;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMergeFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMergeStarted(Lcom/android/ims/internal/IImsCallSession;Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMultipartyStateChanged(Lcom/android/ims/internal/IImsCallSession;Z)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionProgressing(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsStreamMediaProfile;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionResumed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionResumeFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionResumeReceived(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionStarted(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionStartFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionSuppServiceReceived(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsSuppServiceNotification;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionTerminated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionTtyModeReceived(Lcom/android/ims/internal/IImsCallSession;I)V +Lcom/android/ims/internal/IImsCallSessionListener;->callSessionUpdated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V +Lcom/android/ims/internal/IImsRegistrationListener;->registrationAssociatedUriChanged([Landroid/net/Uri;)V +Lcom/android/ims/internal/IImsRegistrationListener;->registrationConnectedWithRadioTech(I)V +Lcom/android/ims/internal/IImsRegistrationListener;->registrationDisconnected(Landroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/IImsRegistrationListener;->registrationFeatureCapabilityChanged(I[I[I)V +Lcom/android/ims/internal/IImsRegistrationListener;->registrationProgressingWithRadioTech(I)V +Lcom/android/ims/internal/IImsRegistrationListener;->voiceMessageCountUpdate(I)V +Lcom/android/ims/internal/IImsUtListener;->utConfigurationCallBarringQueried(Lcom/android/ims/internal/IImsUt;I[Landroid/telephony/ims/ImsSsInfo;)V +Lcom/android/ims/internal/IImsUtListener;->utConfigurationCallForwardQueried(Lcom/android/ims/internal/IImsUt;I[Landroid/telephony/ims/ImsCallForwardInfo;)V +Lcom/android/ims/internal/IImsUtListener;->utConfigurationCallWaitingQueried(Lcom/android/ims/internal/IImsUt;I[Landroid/telephony/ims/ImsSsInfo;)V +Lcom/android/ims/internal/IImsUtListener;->utConfigurationQueried(Lcom/android/ims/internal/IImsUt;ILandroid/os/Bundle;)V +Lcom/android/ims/internal/IImsUtListener;->utConfigurationQueryFailed(Lcom/android/ims/internal/IImsUt;ILandroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/IImsUtListener;->utConfigurationUpdated(Lcom/android/ims/internal/IImsUt;I)V +Lcom/android/ims/internal/IImsUtListener;->utConfigurationUpdateFailed(Lcom/android/ims/internal/IImsUt;ILandroid/telephony/ims/ImsReasonInfo;)V +Lcom/android/ims/internal/uce/common/StatusCode;->getStatusCode()I +Lcom/android/ims/internal/uce/common/UceLong;->getClientId()I +Lcom/android/ims/internal/uce/common/UceLong;->()V +Lcom/android/ims/internal/uce/common/UceLong;->setClientId(I)V +Lcom/android/ims/internal/uce/options/IOptionsListener;->cmdStatus(Lcom/android/ims/internal/uce/options/OptionsCmdStatus;)V +Lcom/android/ims/internal/uce/options/IOptionsListener;->getVersionCb(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/options/IOptionsListener;->incomingOptions(Ljava/lang/String;Lcom/android/ims/internal/uce/options/OptionsCapInfo;I)V +Lcom/android/ims/internal/uce/options/IOptionsListener;->serviceAvailable(Lcom/android/ims/internal/uce/common/StatusCode;)V +Lcom/android/ims/internal/uce/options/IOptionsListener;->serviceUnavailable(Lcom/android/ims/internal/uce/common/StatusCode;)V +Lcom/android/ims/internal/uce/options/IOptionsListener;->sipResponseReceived(Ljava/lang/String;Lcom/android/ims/internal/uce/options/OptionsSipResponse;Lcom/android/ims/internal/uce/options/OptionsCapInfo;)V +Lcom/android/ims/internal/uce/options/IOptionsService;->addListener(ILcom/android/ims/internal/uce/options/IOptionsListener;Lcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/options/IOptionsService;->getContactCap(ILjava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/options/IOptionsService;->getContactListCap(I[Ljava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/options/IOptionsService;->getMyInfo(II)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/options/IOptionsService;->getVersion(I)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/options/IOptionsService;->removeListener(ILcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/options/IOptionsService;->responseIncomingOptions(IIILjava/lang/String;Lcom/android/ims/internal/uce/options/OptionsCapInfo;Z)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/options/IOptionsService;->setMyInfo(ILcom/android/ims/internal/uce/common/CapInfo;I)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/options/IOptionsService$Stub;->()V +Lcom/android/ims/internal/uce/presence/IPresenceListener;->capInfoReceived(Ljava/lang/String;[Lcom/android/ims/internal/uce/presence/PresTupleInfo;)V +Lcom/android/ims/internal/uce/presence/IPresenceListener;->cmdStatus(Lcom/android/ims/internal/uce/presence/PresCmdStatus;)V +Lcom/android/ims/internal/uce/presence/IPresenceListener;->getVersionCb(Ljava/lang/String;)V +Lcom/android/ims/internal/uce/presence/IPresenceListener;->listCapInfoReceived(Lcom/android/ims/internal/uce/presence/PresRlmiInfo;[Lcom/android/ims/internal/uce/presence/PresResInfo;)V +Lcom/android/ims/internal/uce/presence/IPresenceListener;->publishTriggering(Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;)V +Lcom/android/ims/internal/uce/presence/IPresenceListener;->serviceAvailable(Lcom/android/ims/internal/uce/common/StatusCode;)V +Lcom/android/ims/internal/uce/presence/IPresenceListener;->serviceUnAvailable(Lcom/android/ims/internal/uce/common/StatusCode;)V +Lcom/android/ims/internal/uce/presence/IPresenceListener;->sipResponseReceived(Lcom/android/ims/internal/uce/presence/PresSipResponse;)V +Lcom/android/ims/internal/uce/presence/IPresenceListener;->unpublishMessageSent()V +Lcom/android/ims/internal/uce/presence/IPresenceService;->addListener(ILcom/android/ims/internal/uce/presence/IPresenceListener;Lcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/presence/IPresenceService;->getContactCap(ILjava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/presence/IPresenceService;->getContactListCap(I[Ljava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/presence/IPresenceService;->getVersion(I)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/presence/IPresenceService;->publishMyCap(ILcom/android/ims/internal/uce/presence/PresCapInfo;I)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/presence/IPresenceService;->reenableService(II)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/presence/IPresenceService;->removeListener(ILcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/presence/IPresenceService;->setNewFeatureTag(ILjava/lang/String;Lcom/android/ims/internal/uce/presence/PresServiceInfo;I)Lcom/android/ims/internal/uce/common/StatusCode; +Lcom/android/ims/internal/uce/presence/IPresenceService$Stub;->()V +Lcom/android/ims/internal/uce/presence/PresSipResponse;->getCmdId()Lcom/android/ims/internal/uce/presence/PresCmdId; +Lcom/android/ims/internal/uce/presence/PresSipResponse;->getReasonPhrase()Ljava/lang/String; +Lcom/android/ims/internal/uce/presence/PresSipResponse;->getRequestId()I +Lcom/android/ims/internal/uce/presence/PresSipResponse;->getRetryAfter()I +Lcom/android/ims/internal/uce/presence/PresSipResponse;->getSipResponseCode()I +Lcom/android/ims/internal/uce/uceservice/IUceListener;->setStatus(I)V +Lcom/android/ims/internal/uce/uceservice/IUceService;->createOptionsService(Lcom/android/ims/internal/uce/options/IOptionsListener;Lcom/android/ims/internal/uce/common/UceLong;)I +Lcom/android/ims/internal/uce/uceservice/IUceService;->createPresenceService(Lcom/android/ims/internal/uce/presence/IPresenceListener;Lcom/android/ims/internal/uce/common/UceLong;)I +Lcom/android/ims/internal/uce/uceservice/IUceService;->destroyOptionsService(I)V +Lcom/android/ims/internal/uce/uceservice/IUceService;->destroyPresenceService(I)V +Lcom/android/ims/internal/uce/uceservice/IUceService;->getOptionsService()Lcom/android/ims/internal/uce/options/IOptionsService; +Lcom/android/ims/internal/uce/uceservice/IUceService;->getPresenceService()Lcom/android/ims/internal/uce/presence/IPresenceService; +Lcom/android/ims/internal/uce/uceservice/IUceService;->getServiceStatus()Z +Lcom/android/ims/internal/uce/uceservice/IUceService;->isServiceStarted()Z +Lcom/android/ims/internal/uce/uceservice/IUceService;->startService(Lcom/android/ims/internal/uce/uceservice/IUceListener;)Z +Lcom/android/ims/internal/uce/uceservice/IUceService;->stopService()Z +Lcom/android/ims/internal/uce/uceservice/IUceService$Stub;->()V +Lcom/android/internal/location/ILocationProvider;->disable()V +Lcom/android/internal/location/ILocationProvider;->enable()V +Lcom/android/internal/location/ILocationProvider;->getProperties()Lcom/android/internal/location/ProviderProperties; +Lcom/android/internal/location/ILocationProvider;->getStatus(Landroid/os/Bundle;)I +Lcom/android/internal/location/ILocationProvider;->getStatusUpdateTime()J +Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)Z +Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V +Lcom/android/internal/os/BatteryStatsImpl;->getDischargeCurrentLevel()I +Lcom/android/internal/os/BatteryStatsImpl;->getDischargeStartLevel()I +Lcom/android/internal/os/BatteryStatsImpl;->getPhoneOnTime(JI)J +Lcom/android/internal/os/BatteryStatsImpl;->getPhoneSignalScanningTime(JI)J +Lcom/android/internal/os/BatteryStatsImpl;->getPhoneSignalStrengthTime(IJI)J +Lcom/android/internal/os/BatteryStatsImpl;->getScreenBrightnessTime(IJI)J +Lcom/android/internal/os/BatteryStatsImpl;->getWifiOnTime(JI)J +Lcom/android/internal/os/SomeArgs;->obtain()Lcom/android/internal/os/SomeArgs; +Lcom/android/internal/os/SomeArgs;->recycle()V +Lcom/android/internal/telephony/ITelephony;->getDataEnabled(I)Z +Lcom/android/internal/util/IndentingPrintWriter;->decreaseIndent()Lcom/android/internal/util/IndentingPrintWriter; +Lcom/android/internal/util/IndentingPrintWriter;->increaseIndent()Lcom/android/internal/util/IndentingPrintWriter; +Lcom/android/internal/util/IndentingPrintWriter;->(Ljava/io/Writer;Ljava/lang/String;)V +Lcom/android/internal/util/XmlUtils;->beginDocument(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V +Lcom/android/internal/util/XmlUtils;->nextElement(Lorg/xmlpull/v1/XmlPullParser;)V +Ljava/lang/System;->arraycopy([BI[BII)V +Ljava/net/Inet4Address;->ALL:Ljava/net/InetAddress; +Ljava/net/Inet4Address;->ANY:Ljava/net/InetAddress; diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 0b10a35b5d5ead0709c4ac0c5ec8d71084bab9d8..452225cd7da0f1944121b55c0cce36de991227df 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -16,6 +16,8 @@ package android.accessibilityservice; +import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; + import android.annotation.IntDef; import android.content.ComponentName; import android.content.Context; @@ -50,8 +52,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; - /** * This class describes an {@link AccessibilityService}. The system notifies an * {@link AccessibilityService} for {@link android.view.accessibility.AccessibilityEvent}s @@ -409,6 +409,15 @@ public class AccessibilityServiceInfo implements Parcelable { */ public int flags; + /** + * Whether or not the service has crashed and is awaiting restart. Only valid from {@link + * android.view.accessibility.AccessibilityManager#getEnabledAccessibilityServiceList(int)}, + * because that is populated from the internal list of running services. + * + * @hide + */ + public boolean crashed; + /** * The component name the accessibility service. */ @@ -757,6 +766,7 @@ public class AccessibilityServiceInfo implements Parcelable { parcel.writeInt(feedbackType); parcel.writeLong(notificationTimeout); parcel.writeInt(flags); + parcel.writeInt(crashed ? 1 : 0); parcel.writeParcelable(mComponentName, flagz); parcel.writeParcelable(mResolveInfo, 0); parcel.writeString(mSettingsActivityName); @@ -773,6 +783,7 @@ public class AccessibilityServiceInfo implements Parcelable { feedbackType = parcel.readInt(); notificationTimeout = parcel.readLong(); flags = parcel.readInt(); + crashed = parcel.readInt() != 0; mComponentName = parcel.readParcelable(this.getClass().getClassLoader()); mResolveInfo = parcel.readParcelable(null); mSettingsActivityName = parcel.readString(); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 99c5d2b9a92738cd8dae6e853203d7724c5b7c60..3696eaee09138c44417847cf7fe6678e3e60b122 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -124,6 +124,7 @@ import android.widget.Toast; import android.widget.Toolbar; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.ToolbarActionBar; import com.android.internal.app.WindowDecorActionBar; @@ -656,13 +657,13 @@ import java.util.List; * *

Process Lifecycle

* - *

The Android system attempts to keep application process around for as + *

The Android system attempts to keep an application process around for as * long as possible, but eventually will need to remove old processes when - * memory runs low. As described in Activity + * memory runs low. As described in Activity * Lifecycle, the decision about which process to remove is intimately - * tied to the state of the user's interaction with it. In general, there + * tied to the state of the user's interaction with it. In general, there * are four states a process can be in based on the activities running in it, - * listed here in order of importance. The system will kill less important + * listed here in order of importance. The system will kill less important * processes (the last ones) before it resorts to killing more important * processes (the first ones). * @@ -995,9 +996,9 @@ public class Activity extends ContextThemeWrapper * cursors for data being displayed, etc. * *

You can call {@link #finish} from within this function, in - * which case onDestroy() will be immediately called without any of the rest - * of the activity lifecycle ({@link #onStart}, {@link #onResume}, - * {@link #onPause}, etc) executing. + * which case onDestroy() will be immediately called after {@link #onCreate} without any of the + * rest of the activity lifecycle ({@link #onStart}, {@link #onResume}, {@link #onPause}, etc) + * executing. * *

Derived classes must call through to the super class's * implementation of this method. If they do not, an exception will be @@ -7110,6 +7111,12 @@ public class Activity extends ContextThemeWrapper return mParent != null ? mParent.getActivityToken() : mToken; } + /** @hide */ + @VisibleForTesting + public final ActivityThread getActivityThread() { + return mMainThread; + } + final void performCreate(Bundle icicle) { performCreate(icicle, null); } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 2d73ce0c059452f7e6c0ce76bcbede38eeac8dad..a18ba718ecef37b4431213f03591940f2340afaf 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2101,15 +2101,17 @@ public class ActivityManager { private final int mOrientation; private final Rect mContentInsets; private final boolean mReducedResolution; + private final boolean mIsRealSnapshot; private final float mScale; public TaskSnapshot(GraphicBuffer snapshot, int orientation, Rect contentInsets, - boolean reducedResolution, float scale) { + boolean reducedResolution, float scale, boolean isRealSnapshot) { mSnapshot = snapshot; mOrientation = orientation; mContentInsets = new Rect(contentInsets); mReducedResolution = reducedResolution; mScale = scale; + mIsRealSnapshot = isRealSnapshot; } private TaskSnapshot(Parcel source) { @@ -2118,6 +2120,7 @@ public class ActivityManager { mContentInsets = source.readParcelable(null /* classLoader */); mReducedResolution = source.readBoolean(); mScale = source.readFloat(); + mIsRealSnapshot = source.readBoolean(); } /** @@ -2149,6 +2152,14 @@ public class ActivityManager { return mReducedResolution; } + /** + * @return Whether or not the snapshot is a real snapshot or an app-theme generated snapshot + * due to the task having a secure window or having previews disabled. + */ + public boolean isRealSnapshot() { + return mIsRealSnapshot; + } + /** * @return The scale this snapshot was taken in. */ @@ -2168,13 +2179,15 @@ public class ActivityManager { dest.writeParcelable(mContentInsets, 0); dest.writeBoolean(mReducedResolution); dest.writeFloat(mScale); + dest.writeBoolean(mIsRealSnapshot); } @Override public String toString() { return "TaskSnapshot{mSnapshot=" + mSnapshot + " mOrientation=" + mOrientation + " mContentInsets=" + mContentInsets.toShortString() - + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale; + + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale + + " mIsRealSnapshot=" + mIsRealSnapshot; } public static final Creator CREATOR = new Creator() { diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index cab6744e3c81873237a6db8f8ec968e8925c234a..db9d9234aeb8655b012d65ba1fde8f3e500e68f9 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -68,6 +68,13 @@ public abstract class ActivityManagerInternal { public static final int APP_TRANSITION_SNAPSHOT = AppProtoEnums.APP_TRANSITION_SNAPSHOT; // 4 + /** + * Type for {@link #notifyAppTransitionStarting}: The transition was started because it was a + * recents animation and we only needed to wait on the wallpaper. + */ + public static final int APP_TRANSITION_RECENTS_ANIM = + AppProtoEnums.APP_TRANSITION_RECENTS_ANIM; // 5 + /** * The bundle key to extract the assist data. */ @@ -378,4 +385,10 @@ public abstract class ActivityManagerInternal { * Returns a list that contains the memory stats for currently running processes. */ public abstract List getMemoryStateForProcesses(); + + /** + * This enforces {@code func} can only be called if either the caller is Recents activity or + * has {@code permission}. + */ + public abstract void enforceCallerIsRecentsOrHasPermission(String permission, String func); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 1253416970a8968a71fb09ea393dfc9ada36efab..d802f8148985ca168a5953c981d0e965201b2c07 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -30,12 +30,15 @@ import android.annotation.Nullable; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.backup.BackupAgent; +import android.app.servertransaction.ActivityLifecycleItem; import android.app.servertransaction.ActivityLifecycleItem.LifecycleState; +import android.app.servertransaction.ActivityRelaunchItem; import android.app.servertransaction.ActivityResultItem; import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.PendingTransactionActions; import android.app.servertransaction.PendingTransactionActions.StopInfo; import android.app.servertransaction.TransactionExecutor; +import android.app.servertransaction.TransactionExecutorHelper; import android.content.BroadcastReceiver; import android.content.ComponentCallbacks2; import android.content.ComponentName; @@ -64,6 +67,7 @@ import android.database.sqlite.SQLiteDebug; import android.database.sqlite.SQLiteDebug.DbStats; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.ImageDecoder; import android.hardware.display.DisplayManagerGlobal; import android.net.ConnectivityManager; import android.net.IConnectivityManager; @@ -519,6 +523,10 @@ public final class ActivityThread extends ClientTransactionHandler { return activityInfo.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS; } + public boolean isVisibleFromServer() { + return activity != null && activity.mVisibleFromServer; + } + public String toString() { ComponentName componentName = intent != null ? intent.getComponent() : null; return "ActivityRecord{" @@ -704,7 +712,7 @@ public final class ActivityThread extends ClientTransactionHandler { streamingOutput); profiling = true; } catch (RuntimeException e) { - Slog.w(TAG, "Profiling failed on path " + profileFile); + Slog.w(TAG, "Profiling failed on path " + profileFile, e); try { profileFd.close(); profileFd = null; @@ -1796,6 +1804,7 @@ public final class ActivityThread extends ClientTransactionHandler { // message is handled. transaction.recycle(); } + // TODO(lifecycler): Recycle locally scheduled transactions. break; } Object obj = msg.obj; @@ -3722,16 +3731,27 @@ public final class ActivityThread extends ClientTransactionHandler { //Slog.i(TAG, "Running services: " + mServices); } - ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String reason) { + ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, + String reason) { ActivityClientRecord r = mActivities.get(token); if (localLOGV) Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); if (r != null && !r.activity.mFinished) { if (r.getLifecycleState() == ON_RESUME) { - throw new IllegalStateException( - "Trying to resume activity which is already resumed"); + if (!finalStateRequest) { + final RuntimeException e = new IllegalStateException( + "Trying to resume activity which is already resumed"); + Slog.e(TAG, e.getMessage(), e); + Slog.e(TAG, r.getStateString()); + // TODO(lifecycler): A double resume request is possible when an activity + // receives two consequent transactions with relaunch requests and "resumed" + // final state requests and the second relaunch is omitted. We still try to + // handle two resume requests for the final state. For cases other than this + // one, we don't expect it to happen. + } + return null; } - if (clearHide) { + if (finalStateRequest) { r.hideForNow = false; r.activity.mStartedActivity = false; } @@ -3782,7 +3802,7 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, + public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. @@ -3790,7 +3810,7 @@ public final class ActivityThread extends ClientTransactionHandler { mSomeActivitiesChanged = true; // TODO Push resumeArgs into the activity for consideration - final ActivityClientRecord r = performResumeActivity(token, clearHide, reason); + final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); if (r != null) { final Activity a = r.activity; @@ -4022,9 +4042,11 @@ public final class ActivityThread extends ClientTransactionHandler { r.setState(ON_PAUSE); } + /** Called from {@link LocalActivityManager}. */ final void performStopActivity(IBinder token, boolean saveState, String reason) { ActivityClientRecord r = mActivities.get(token); - performStopActivityInner(r, null, false, saveState, reason); + performStopActivityInner(r, null /* stopInfo */, false /* keepShown */, saveState, + false /* finalStateRequest */, reason); } private static final class ProviderRefCount { @@ -4056,9 +4078,16 @@ public final class ActivityThread extends ClientTransactionHandler { * it the result when it is done, but the window may still be visible. * For the client, we want to call onStop()/onStart() to indicate when * the activity's UI visibility changes. + * @param r Target activity client record. + * @param info Action that will report activity stop to server. + * @param keepShown Flag indicating whether the activity is still shown. + * @param saveState Flag indicating whether the activity state should be saved. + * @param finalStateRequest Flag indicating if this call is handling final lifecycle state + * request for a transaction. + * @param reason Reason for performing this operation. */ private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown, - boolean saveState, String reason) { + boolean saveState, boolean finalStateRequest, String reason) { if (localLOGV) Slog.v(TAG, "Performing stop of " + r); if (r != null) { if (!keepShown && r.stopped) { @@ -4068,11 +4097,13 @@ public final class ActivityThread extends ClientTransactionHandler { // if the activity isn't resumed. return; } - RuntimeException e = new RuntimeException( - "Performing stop of activity that is already stopped: " - + r.intent.getComponent().toShortString()); - Slog.e(TAG, e.getMessage(), e); - Slog.e(TAG, r.getStateString()); + if (!finalStateRequest) { + final RuntimeException e = new RuntimeException( + "Performing stop of activity that is already stopped: " + + r.intent.getComponent().toShortString()); + Slog.e(TAG, e.getMessage(), e); + Slog.e(TAG, r.getStateString()); + } } // One must first be paused before stopped... @@ -4165,12 +4196,13 @@ public final class ActivityThread extends ClientTransactionHandler { @Override public void handleStopActivity(IBinder token, boolean show, int configChanges, - PendingTransactionActions pendingActions, String reason) { + PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) { final ActivityClientRecord r = mActivities.get(token); r.activity.mConfigChangeFlags |= configChanges; final StopInfo stopInfo = new StopInfo(); - performStopActivityInner(r, stopInfo, show, true, reason); + performStopActivityInner(r, stopInfo, show, true /* saveState */, finalStateRequest, + reason); if (localLOGV) Slog.v( TAG, "Finishing stop of " + r + ": show=" + show @@ -4222,7 +4254,8 @@ public final class ActivityThread extends ClientTransactionHandler { } if (!show && !r.stopped) { - performStopActivityInner(r, null, show, false, "handleWindowVisibility"); + performStopActivityInner(r, null /* stopInfo */, show, false /* saveState */, + false /* finalStateRequest */, "handleWindowVisibility"); } else if (show && r.stopped) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. @@ -4698,14 +4731,25 @@ public final class ActivityThread extends ClientTransactionHandler { return; } - // TODO(b/73747058): Investigate converting this to use transaction to relaunch. - handleRelaunchActivityInner(r, 0 /* configChanges */, null /* pendingResults */, - null /* pendingIntents */, null /* pendingActions */, prevState != ON_RESUME, - r.overrideConfig, "handleRelaunchActivityLocally"); - // Restore back to the previous state before relaunch if needed. - if (prevState != r.getLifecycleState()) { - mTransactionExecutor.cycleToPath(r, prevState); + // Initialize a relaunch request. + final MergedConfiguration mergedConfiguration = new MergedConfiguration( + r.createdConfig != null ? r.createdConfig : mConfiguration, + r.overrideConfig); + final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain( + null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */, + mergedConfiguration, r.mPreserveWindow); + // Make sure to match the existing lifecycle state in the end of the transaction. + final ActivityLifecycleItem lifecycleRequest = + TransactionExecutorHelper.getLifecycleRequestForCurrentState(r); + // Schedule the transaction. + final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token); + transaction.addCallback(activityRelaunchItem); + transaction.setLifecycleStateRequest(lifecycleRequest); + try { + mAppThread.scheduleTransaction(transaction); + } catch (RemoteException e) { + // Local scheduling } } @@ -5540,6 +5584,13 @@ public final class ActivityThread extends ClientTransactionHandler { Message.updateCheckRecycle(data.appInfo.targetSdkVersion); + // Prior to P, internal calls to decode Bitmaps used BitmapFactory, + // which may scale up to account for density. In P, we switched to + // ImageDecoder, which skips the upscale to save memory. ImageDecoder + // needs to still scale up in older apps, in case they rely on the + // size of the Bitmap without considering its density. + ImageDecoder.sApiLevel = data.appInfo.targetSdkVersion; + /* * Before spawning a new process, reset the time zone to be the system time zone. * This needs to be done because the system time zone could have changed after the @@ -5648,6 +5699,7 @@ public final class ActivityThread extends ClientTransactionHandler { // Allow application-generated systrace messages if we're debuggable. boolean isAppDebuggable = (data.appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; Trace.setAppTracingAllowed(isAppDebuggable); + ThreadedRenderer.setDebuggingEnabled(isAppDebuggable || Build.IS_DEBUGGABLE); if (isAppDebuggable && data.enableBinderTracking) { Binder.enableTracing(); } @@ -5706,6 +5758,8 @@ public final class ActivityThread extends ClientTransactionHandler { } finally { StrictMode.setThreadPolicyMask(oldMask); } + } else { + ThreadedRenderer.setIsolatedProcess(true); } // If we use profiles, setup the dex reporter to notify package manager diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 5d0143a505f321328cce47dbc38f498bca55da94..7032a2fe21cf0e16236bf25df13448fb946af4d7 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -27,6 +27,7 @@ import android.os.RemoteException; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; +import android.view.IWindowManager; import android.view.InputDevice; import android.view.InputEvent; import android.view.MotionEvent; @@ -308,8 +309,14 @@ public class ActivityView extends ViewGroup { return; } - mInputForwarder = InputManager.getInstance().createInputForwarder( - mVirtualDisplay.getDisplay().getDisplayId()); + final int displayId = mVirtualDisplay.getDisplay().getDisplayId(); + final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + try { + wm.dontOverrideDisplayInfo(displayId); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + mInputForwarder = InputManager.getInstance().createInputForwarder(displayId); mTaskStackListener = new TaskBackgroundChangeListener(); try { mActivityManager.registerTaskStackListener(mTaskStackListener); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 05a9861f5a20b47564c731e72d23ceeceebcd77d..4690211f4667d5e7ea0961034e7c172b73315c46 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -499,13 +499,14 @@ public class AppOpsManager { public static final String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background"; /** @hide */ @SystemApi @TestApi - public static final String OPSTR_CHANGE_WIFI_STATE = "change_wifi_state"; + public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state"; /** @hide */ @SystemApi @TestApi - public static final String OPSTR_REQUEST_DELETE_PACKAGES = "request_delete_packages"; + public static final String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages"; /** @hide */ @SystemApi @TestApi - public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = "bind_accessibility_service"; + public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = + "android:bind_accessibility_service"; // Warning: If an permission is added here it also has to be added to // com.android.packageinstaller.permission.utils.EventLogger @@ -1609,6 +1610,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 +1630,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 +1662,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); @@ -1668,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 @@ -1679,6 +1703,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 +1715,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 81cbbcafe8c421936e81113d86b27009c8c2d27d..4531f53bd86fe3f1b19e39b48ee5b889535c0942 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; *

*/ public class Application extends ContextWrapper implements ComponentCallbacks2 { + private static final String TAG = "Application"; private ArrayList mComponentCallbacks = new ArrayList(); private ArrayList mActivityLifecycleCallbacks = @@ -191,6 +193,16 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } } + /** + * Returns the name of the current process. A package's default process name + * is the same as its package name. Non-default processes will look like + * "$PACKAGE_NAME:$NAME", where $NAME corresponds to an android:process + * attribute within AndroidManifest.xml. + */ + public static String getProcessName() { + return ActivityThread.currentProcessName(); + } + // ------------------ Internal API ------------------ /** @@ -308,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 @@ -328,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; } -} \ No newline at end of file +} diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 21fb18a212a8e1ba764e25861b62dd63386bcfa5..b8c4ef783a608c03eb7ab61f1d200b63b7562c9d 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -20,6 +20,7 @@ import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; +import android.annotation.UserIdInt; import android.annotation.XmlRes; import android.content.ComponentName; import android.content.ContentResolver; @@ -1031,18 +1032,24 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public ResolveInfo resolveService(Intent intent, int flags) { + public ResolveInfo resolveServiceAsUser(Intent intent, @ResolveInfoFlags int flags, + @UserIdInt int userId) { try { return mPM.resolveService( intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), flags, - mContext.getUserId()); + userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + @Override + public ResolveInfo resolveService(Intent intent, int flags) { + return resolveServiceAsUser(intent, flags, mContext.getUserId()); + } + @Override @SuppressWarnings("unchecked") public List queryIntentServicesAsUser(Intent intent, int flags, int userId) { diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 6bc66ecdb2618e89f913bbc7f31045ba259d2f2e..961bca23c91afac92d2ca8a584160e70afda6451 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -67,13 +67,30 @@ public abstract class ClientTransactionHandler { public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, PendingTransactionActions pendingActions, String reason); - /** Resume the activity. */ - public abstract void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, - String reason); + /** + * Resume the activity. + * @param token Target activity token. + * @param finalStateRequest Flag indicating if this call is handling final lifecycle state + * request for a transaction. + * @param isForward Flag indicating if next transition is forward. + * @param reason Reason for performing this operation. + */ + public abstract void handleResumeActivity(IBinder token, boolean finalStateRequest, + boolean isForward, String reason); - /** Stop the activity. */ + /** + * Stop the activity. + * @param token Target activity token. + * @param show Flag indicating whether activity is still shown. + * @param configChanges Activity configuration changes. + * @param pendingActions Pending actions to be used on this or later stages of activity + * transaction. + * @param finalStateRequest Flag indicating if this call is handling final lifecycle state + * request for a transaction. + * @param reason Reason for performing this operation. + */ public abstract void handleStopActivity(IBinder token, boolean show, int configChanges, - PendingTransactionActions pendingActions, String reason); + PendingTransactionActions pendingActions, boolean finalStateRequest, String reason); /** Report that activity was stopped to server. */ public abstract void reportStop(PendingTransactionActions pendingActions); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 13a6be557dae6f180e4ed248d81ea5950d92e53a..c6568e16086c0b3c1979cb61ff9d311717640a8d 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -89,6 +89,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Set; /** @@ -762,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.). */ @@ -834,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 CATEGORY_* constants) * that best describes this Notification. May be used by the system for ranking and filtering. @@ -2572,6 +2599,80 @@ public class Notification implements Parcelable } }; + /** + * @hide + */ + public static boolean areActionsVisiblyDifferent(Notification first, Notification second) { + Notification.Action[] firstAs = first.actions; + Notification.Action[] secondAs = second.actions; + if (firstAs == null && secondAs != null || firstAs != null && secondAs == null) { + return true; + } + if (firstAs != null && secondAs != null) { + if (firstAs.length != secondAs.length) { + return true; + } + for (int i = 0; i < firstAs.length; i++) { + if (!Objects.equals(firstAs[i].title, secondAs[i].title)) { + return true; + } + RemoteInput[] firstRs = firstAs[i].getRemoteInputs(); + RemoteInput[] secondRs = secondAs[i].getRemoteInputs(); + if (firstRs == null) { + firstRs = new RemoteInput[0]; + } + if (secondRs == null) { + secondRs = new RemoteInput[0]; + } + if (firstRs.length != secondRs.length) { + return true; + } + for (int j = 0; j < firstRs.length; j++) { + if (!Objects.equals(firstRs[j].getLabel(), secondRs[j].getLabel())) { + return true; + } + CharSequence[] firstCs = firstRs[i].getChoices(); + CharSequence[] secondCs = secondRs[i].getChoices(); + if (firstCs == null) { + firstCs = new CharSequence[0]; + } + if (secondCs == null) { + secondCs = new CharSequence[0]; + } + if (firstCs.length != secondCs.length) { + return true; + } + for (int k = 0; k < firstCs.length; k++) { + if (!Objects.equals(firstCs[k], secondCs[k])) { + return true; + } + } + } + } + } + return false; + } + + /** + * @hide + */ + public static boolean areStyledNotificationsVisiblyDifferent(Builder first, Builder second) { + if (first.getStyle() == null) { + return second.getStyle() != null; + } + if (second.getStyle() == null) { + return true; + } + return first.getStyle().areNotificationsVisiblyDifferent(second.getStyle()); + } + + /** + * @hide + */ + public static boolean areRemoteViewsChanged(Builder first, Builder second) { + return !first.usesStandardHeader() || !second.usesStandardHeader(); + } + /** * Parcelling creates multiple copies of objects in {@code extras}. Fix them. *

@@ -4012,6 +4113,13 @@ public class Notification implements Parcelable return this; } + /** + * Returns the style set by {@link #setStyle(Style)}. + */ + public Style getStyle() { + return mStyle; + } + /** * Specify the value of {@link #visibility}. * @@ -5469,6 +5577,24 @@ public class Notification implements Parcelable public void setRebuildStyledRemoteViews(boolean rebuild) { mRebuildStyledRemoteViews = rebuild; } + + /** + * Get the text that should be displayed in the statusBar when heads upped. This is + * usually just the app name, but may be different depending on the style. + * + * @param publicMode If true, return a text that is safe to display in public. + * + * @hide + */ + public CharSequence getHeadsUpStatusBarText(boolean publicMode) { + if (mStyle != null && !publicMode) { + CharSequence text = mStyle.getHeadsUpStatusBarText(); + if (!TextUtils.isEmpty(text)) { + return text; + } + } + return loadHeaderAppName(); + } } /** @@ -5841,6 +5967,21 @@ public class Notification implements Parcelable */ public void validate(Context context) { } + + /** + * @hide + */ + public abstract boolean areNotificationsVisiblyDifferent(Style other); + + /** + * @return the the text that should be displayed in the statusBar when heads-upped. + * If {@code null} is returned, the default implementation will be used. + * + * @hide + */ + public CharSequence getHeadsUpStatusBarText() { + return null; + } } /** @@ -5893,6 +6034,13 @@ public class Notification implements Parcelable return this; } + /** + * @hide + */ + public Bitmap getBigPicture() { + return mPicture; + } + /** * Provide the bitmap to be used as the payload for the BigPicture notification. */ @@ -6033,6 +6181,18 @@ public class Notification implements Parcelable public boolean hasSummaryInHeader() { return false; } + + /** + * @hide + */ + @Override + public boolean areNotificationsVisiblyDifferent(Style other) { + if (other == null || getClass() != other.getClass()) { + return true; + } + BigPictureStyle otherS = (BigPictureStyle) other; + return !Objects.equals(getBigPicture(), otherS.getBigPicture()); + } } /** @@ -6093,6 +6253,13 @@ public class Notification implements Parcelable return this; } + /** + * @hide + */ + public CharSequence getBigText() { + return mBigText; + } + /** * @hide */ @@ -6165,6 +6332,18 @@ public class Notification implements Parcelable return contentView; } + /** + * @hide + */ + @Override + public boolean areNotificationsVisiblyDifferent(Style other) { + if (other == null || getClass() != other.getClass()) { + return true; + } + BigTextStyle newS = (BigTextStyle) other; + return !Objects.equals(getBigText(), newS.getBigText()); + } + static void applyBigTextContentView(Builder builder, RemoteViews contentView, CharSequence bigTextText) { contentView.setTextViewText(R.id.big_text, builder.processTextSpans(bigTextText)); @@ -6251,6 +6430,23 @@ public class Notification implements Parcelable } } + /** + * @return the the text that should be displayed in the statusBar when heads upped. + * If {@code null} is returned, the default implementation will be used. + * + * @hide + */ + @Override + public CharSequence getHeadsUpStatusBarText() { + CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle) + ? super.mBigContentTitle + : mConversationTitle; + if (!TextUtils.isEmpty(conversationTitle) && !hasOnlyWhiteSpaceSenders()) { + return conversationTitle; + } + return null; + } + /** * @return the user to be displayed for any replies sent by the user */ @@ -6507,6 +6703,58 @@ public class Notification implements Parcelable return remoteViews; } + /** + * @hide + */ + @Override + public boolean areNotificationsVisiblyDifferent(Style other) { + if (other == null || getClass() != other.getClass()) { + return true; + } + MessagingStyle newS = (MessagingStyle) other; + List oldMs = getMessages(); + List newMs = newS.getMessages(); + + if (oldMs == null) { + oldMs = new ArrayList<>(); + } + if (newMs == null) { + newMs = new ArrayList<>(); + } + + int n = oldMs.size(); + if (n != newMs.size()) { + return true; + } + for (int i = 0; i < n; i++) { + MessagingStyle.Message oldM = oldMs.get(i); + MessagingStyle.Message newM = newMs.get(i); + if (!Objects.equals(oldM.getText(), newM.getText())) { + return true; + } + if (!Objects.equals(oldM.getDataUri(), newM.getDataUri())) { + return true; + } + CharSequence oldSender = oldM.getSenderPerson() == null ? oldM.getSender() + : oldM.getSenderPerson().getName(); + CharSequence newSender = newM.getSenderPerson() == null ? newM.getSender() + : newM.getSenderPerson().getName(); + if (!Objects.equals(oldSender, newSender)) { + return true; + } + + String oldKey = oldM.getSenderPerson() == null + ? null : oldM.getSenderPerson().getKey(); + String newKey = newM.getSenderPerson() == null + ? null : newM.getSenderPerson().getKey(); + if (!Objects.equals(oldKey, newKey)) { + return true; + } + // Other fields (like timestamp) intentionally excluded + } + return false; + } + private Message findLatestIncomingMessage() { return findLatestIncomingMessage(mMessages); } @@ -6935,6 +7183,13 @@ public class Notification implements Parcelable return this; } + /** + * @hide + */ + public ArrayList getLines() { + return mTexts; + } + /** * @hide */ @@ -7016,6 +7271,18 @@ public class Notification implements Parcelable return contentView; } + /** + * @hide + */ + @Override + public boolean areNotificationsVisiblyDifferent(Style other) { + if (other == null || getClass() != other.getClass()) { + return true; + } + InboxStyle newS = (InboxStyle) other; + return !Objects.equals(getLines(), newS.getLines()); + } + private void handleInboxImageMargin(RemoteViews contentView, int id, boolean first) { int endMargin = 0; if (first) { @@ -7179,6 +7446,18 @@ public class Notification implements Parcelable } } + /** + * @hide + */ + @Override + public boolean areNotificationsVisiblyDifferent(Style other) { + if (other == null || getClass() != other.getClass()) { + return true; + } + // All fields to compare are on the Notification object + return false; + } + private RemoteViews generateMediaActionButton(Action action, int color) { final boolean tombstone = (action.actionIntent == null); RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(), @@ -7388,6 +7667,18 @@ public class Notification implements Parcelable } remoteViews.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin); } + + /** + * @hide + */ + @Override + public boolean areNotificationsVisiblyDifferent(Style other) { + if (other == null || getClass() != other.getClass()) { + return true; + } + // Comparison done for all custom RemoteViews, independent of style + return false; + } } /** @@ -7478,6 +7769,18 @@ public class Notification implements Parcelable return makeBigContentViewWithCustomContent(customRemoteView); } + /** + * @hide + */ + @Override + public boolean areNotificationsVisiblyDifferent(Style other) { + if (other == null || getClass() != other.getClass()) { + return true; + } + // Comparison done for all custom RemoteViews, independent of style + return false; + } + private RemoteViews buildIntoRemoteView(RemoteViews remoteViews, int id, RemoteViews customContent) { if (customContent != null) { @@ -7501,6 +7804,8 @@ public class Notification implements Parcelable @Nullable private Icon mIcon; @Nullable private String mUri; @Nullable private String mKey; + private boolean mBot; + private boolean mImportant; protected Person(Parcel in) { mName = in.readCharSequence(); @@ -7509,6 +7814,8 @@ public class Notification implements Parcelable } mUri = in.readString(); mKey = in.readString(); + mImportant = in.readBoolean(); + mBot = in.readBoolean(); } /** @@ -7585,6 +7892,27 @@ public class Notification implements Parcelable return this; } + /** + * Sets whether this is an important person. Use this method to denote users who frequently + * interact with the user of this device, when it is not possible to refer to the user + * by {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}. + * + * @param isImportant {@code true} if this is an important person, {@code false} otherwise. + */ + public Person setImportant(boolean isImportant) { + mImportant = isImportant; + return this; + } + + /** + * Sets whether this person is a machine rather than a human. + * + * @param isBot {@code true} if this person is a machine, {@code false} otherwise. + */ + public Person setBot(boolean isBot) { + mBot = isBot; + return this; + } /** * @return the uri provided for this person or {@code null} if no Uri was provided @@ -7618,6 +7946,20 @@ public class Notification implements Parcelable return mKey; } + /** + * @return whether this Person is a machine. + */ + public boolean isBot() { + return mBot; + } + + /** + * @return whether this Person is important. + */ + public boolean isImportant() { + return mImportant; + } + /** * @return the URI associated with this person, or "name:mName" otherwise * @hide @@ -7648,6 +7990,8 @@ public class Notification implements Parcelable } dest.writeString(mUri); dest.writeString(mKey); + dest.writeBoolean(mImportant); + dest.writeBoolean(mBot); } public static final Creator CREATOR = new Creator() { diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java index c2c91c2bcbd6f9f7769ac7a68ecc1d35867e99a9..4a6fa8c2d7a27ef2b52152da1aada7db5ca08811 100644 --- a/core/java/android/app/StatsManager.java +++ b/core/java/android/app/StatsManager.java @@ -16,6 +16,7 @@ package android.app; import android.Manifest; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.os.IBinder; @@ -53,6 +54,12 @@ public final class StatsManager { */ public static final String EXTRA_STATS_SUBSCRIPTION_RULE_ID = "android.app.extra.STATS_SUBSCRIPTION_RULE_ID"; + /** + * List of the relevant statsd_config.proto's BroadcastSubscriberDetails.cookie. + * Obtain using {@link android.content.Intent#getStringArrayListExtra(String)}. + */ + public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = + "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES"; /** * Extra of a {@link android.os.StatsDimensionsValue} representing sliced dimension value * information. @@ -74,14 +81,6 @@ public final class StatsManager { public StatsManager() { } - /** - * Temporary. Will be deleted. - */ - @RequiresPermission(Manifest.permission.DUMP) - public boolean addConfiguration(long configKey, byte[] config, String a, String b) { - return addConfiguration(configKey, config); - } - /** * Clients can send a configuration and simultaneously registers the name of a broadcast * receiver that listens for when it should request data. @@ -97,12 +96,12 @@ public final class StatsManager { try { IStatsManager service = getIStatsManagerLocked(); if (service == null) { - if (DEBUG) Slog.d(TAG, "Failed to find statsd when adding configuration"); + Slog.e(TAG, "Failed to find statsd when adding configuration"); return false; } return service.addConfiguration(configKey, config); } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when adding configuration"); + Slog.e(TAG, "Failed to connect to statsd when adding configuration"); return false; } } @@ -120,12 +119,12 @@ public final class StatsManager { try { IStatsManager service = getIStatsManagerLocked(); if (service == null) { - if (DEBUG) Slog.d(TAG, "Failed to find statsd when removing configuration"); + Slog.e(TAG, "Failed to find statsd when removing configuration"); return false; } return service.removeConfiguration(configKey); } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when removing configuration"); + Slog.e(TAG, "Failed to connect to statsd when removing configuration"); return false; } } @@ -146,7 +145,8 @@ public final class StatsManager { * {@link #EXTRA_STATS_CONFIG_UID}, * {@link #EXTRA_STATS_CONFIG_KEY}, * {@link #EXTRA_STATS_SUBSCRIPTION_ID}, - * {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID}, and + * {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID}, + * {@link #EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES}, and * {@link #EXTRA_STATS_DIMENSIONS_VALUE}. *

* This function can only be called by the owner (uid) of the config. It must be called each @@ -166,7 +166,7 @@ public final class StatsManager { try { IStatsManager service = getIStatsManagerLocked(); if (service == null) { - Slog.w(TAG, "Failed to find statsd when adding broadcast subscriber"); + Slog.e(TAG, "Failed to find statsd when adding broadcast subscriber"); return false; } if (pendingIntent != null) { @@ -177,7 +177,7 @@ public final class StatsManager { return service.unsetBroadcastSubscriber(configKey, subscriberId); } } catch (RemoteException e) { - Slog.w(TAG, "Failed to connect to statsd when adding broadcast subscriber", e); + Slog.e(TAG, "Failed to connect to statsd when adding broadcast subscriber", e); return false; } } @@ -203,7 +203,7 @@ public final class StatsManager { try { IStatsManager service = getIStatsManagerLocked(); if (service == null) { - Slog.d(TAG, "Failed to find statsd when registering data listener."); + Slog.e(TAG, "Failed to find statsd when registering data listener."); return false; } if (pendingIntent == null) { @@ -215,7 +215,7 @@ public final class StatsManager { } } catch (RemoteException e) { - Slog.d(TAG, "Failed to connect to statsd when registering data listener."); + Slog.e(TAG, "Failed to connect to statsd when registering data listener."); return false; } } @@ -226,20 +226,21 @@ public final class StatsManager { * the retrieved metrics from statsd memory. * * @param configKey Configuration key to retrieve data from. - * @return Serialized ConfigMetricsReportList proto. Returns null on failure. + * @return Serialized ConfigMetricsReportList proto. Returns null on failure (eg, if statsd + * crashed). */ @RequiresPermission(Manifest.permission.DUMP) - public byte[] getData(long configKey) { + public @Nullable byte[] getData(long configKey) { synchronized (this) { try { IStatsManager service = getIStatsManagerLocked(); if (service == null) { - if (DEBUG) Slog.d(TAG, "Failed to find statsd when getting data"); + Slog.e(TAG, "Failed to find statsd when getting data"); return null; } return service.getData(configKey); } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting data"); + Slog.e(TAG, "Failed to connect to statsd when getting data"); return null; } } @@ -250,20 +251,20 @@ public final class StatsManager { * the actual metrics themselves (metrics must be collected via {@link #getData(String)}. * This getter is not destructive and will not reset any metrics/counters. * - * @return Serialized StatsdStatsReport proto. Returns null on failure. + * @return Serialized StatsdStatsReport proto. Returns null on failure (eg, if statsd crashed). */ @RequiresPermission(Manifest.permission.DUMP) - public byte[] getMetadata() { + public @Nullable byte[] getMetadata() { synchronized (this) { try { IStatsManager service = getIStatsManagerLocked(); if (service == null) { - if (DEBUG) Slog.d(TAG, "Failed to find statsd when getting metadata"); + Slog.e(TAG, "Failed to find statsd when getting metadata"); return null; } return service.getMetadata(); } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting metadata"); + Slog.e(TAG, "Failed to connect to statsd when getting metadata"); return null; } } diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 85a9be35587877b1db6860e56701cf52af40e757..b83b44d295b464d21f73f18a7e2eb4f6d7c4fa93 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -74,11 +74,12 @@ public class StatusBarManager { public static final int DISABLE2_SYSTEM_ICONS = 1 << 1; public static final int DISABLE2_NOTIFICATION_SHADE = 1 << 2; public static final int DISABLE2_GLOBAL_ACTIONS = 1 << 3; + public static final int DISABLE2_ROTATE_SUGGESTIONS = 1 << 4; public static final int DISABLE2_NONE = 0x00000000; public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS - | DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS; + | DISABLE2_NOTIFICATION_SHADE | DISABLE2_GLOBAL_ACTIONS | DISABLE2_ROTATE_SUGGESTIONS; @IntDef(flag = true, prefix = { "DISABLE2_" }, value = { DISABLE2_NONE, @@ -86,7 +87,8 @@ public class StatusBarManager { DISABLE2_QUICK_SETTINGS, DISABLE2_SYSTEM_ICONS, DISABLE2_NOTIFICATION_SHADE, - DISABLE2_GLOBAL_ACTIONS + DISABLE2_GLOBAL_ACTIONS, + DISABLE2_ROTATE_SUGGESTIONS }) @Retention(RetentionPolicy.SOURCE) public @interface Disable2Flags {} diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java index ed2aaf915ef25984991995378d281525741be638..5fbe5b3984885055a57583d6f995e1a23eb6e468 100644 --- a/core/java/android/app/admin/DeviceAdminInfo.java +++ b/core/java/android/app/admin/DeviceAdminInfo.java @@ -16,31 +16,31 @@ package android.app.admin; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; -import android.content.res.Resources.NotFoundException; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; +import android.os.PersistableBundle; import android.util.AttributeSet; import android.util.Log; import android.util.Printer; import android.util.SparseArray; import android.util.Xml; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -266,6 +266,12 @@ public final class DeviceAdminInfo implements Parcelable { */ int mUsesPolicies; + /** + * Whether this administrator can be a target in an ownership transfer. + * + * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle) + */ + boolean mSupportsTransferOwnership; /** * Constructor. @@ -347,6 +353,12 @@ public final class DeviceAdminInfo implements Parcelable { + getComponent() + ": " + policyName); } } + } else if (tagName.equals("support-transfer-ownership")) { + if (parser.next() != XmlPullParser.END_TAG) { + throw new XmlPullParserException( + "support-transfer-ownership tag must be empty."); + } + mSupportsTransferOwnership = true; } } } catch (NameNotFoundException e) { @@ -360,6 +372,7 @@ public final class DeviceAdminInfo implements Parcelable { DeviceAdminInfo(Parcel source) { mActivityInfo = ActivityInfo.CREATOR.createFromParcel(source); mUsesPolicies = source.readInt(); + mSupportsTransferOwnership = source.readBoolean(); } /** @@ -458,6 +471,13 @@ public final class DeviceAdminInfo implements Parcelable { return sRevKnownPolicies.get(policyIdent).tag; } + /** + * Return true if this administrator can be a target in an ownership transfer. + */ + public boolean supportsTransferOwnership() { + return mSupportsTransferOwnership; + } + /** @hide */ public ArrayList getUsedPolicies() { ArrayList res = new ArrayList(); @@ -502,6 +522,7 @@ public final class DeviceAdminInfo implements Parcelable { public void writeToParcel(Parcel dest, int flags) { mActivityInfo.writeToParcel(dest, flags); dest.writeInt(mUsesPolicies); + dest.writeBoolean(mSupportsTransferOwnership); } /** diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index 8c30fc4037132f10e715691aa1f3c1e53408dc20..1c9477d08cb3fd0da76837816b2d01def6003b36 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -505,31 +505,6 @@ public class DeviceAdminReceiver extends BroadcastReceiver { public static final String EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE = "android.app.extra.TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE"; - /** - * Name under which a device administration component indicates whether it supports transfer of - * ownership. This meta-data is of type boolean. A value of true - * allows this administrator to be used as a target administrator for a transfer. If the value - * is false, ownership cannot be transferred to this administrator. The default - * value is false. - *

This metadata is used to avoid ownership transfer migration to an administrator with a - * version which does not yet support it. - *

Usage: - *

-     * <receiver name="..." android:permission="android.permission.BIND_DEVICE_ADMIN">
-     *     <meta-data
-     *         android:name="android.app.device_admin"
-     *         android:resource="@xml/..." />
-     *     <meta-data
-     *         android:name="android.app.support_transfer_ownership"
-     *         android:value="true" />
-     * </receiver>
-     * 
- * - * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle) - */ - public static final String SUPPORT_TRANSFER_OWNERSHIP_META_DATA = - "android.app.support_transfer_ownership"; - private DevicePolicyManager mManager; private ComponentName mWho; diff --git a/core/java/android/app/admin/DevicePolicyCache.java b/core/java/android/app/admin/DevicePolicyCache.java new file mode 100644 index 0000000000000000000000000000000000000000..fbb8ddfecad28101eed1ada7bbb8efd8a22338cb --- /dev/null +++ b/core/java/android/app/admin/DevicePolicyCache.java @@ -0,0 +1,57 @@ +/* + * 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.app.admin; + +import android.annotation.UserIdInt; + +import com.android.server.LocalServices; + +/** + * Stores a copy of the set of device policies maintained by {@link DevicePolicyManager} that + * can be accessed from any place without risking dead locks. + * + * @hide + */ +public abstract class DevicePolicyCache { + protected DevicePolicyCache() { + } + + /** + * @return the instance. + */ + public static DevicePolicyCache getInstance() { + final DevicePolicyManagerInternal dpmi = + LocalServices.getService(DevicePolicyManagerInternal.class); + return (dpmi != null) ? dpmi.getDevicePolicyCache() : EmptyDevicePolicyCache.INSTANCE; + } + + /** + * See {@link DevicePolicyManager#getScreenCaptureDisabled} + */ + public abstract boolean getScreenCaptureDisabled(@UserIdInt int userHandle); + + /** + * Empty implementation. + */ + private static class EmptyDevicePolicyCache extends DevicePolicyCache { + private static final EmptyDevicePolicyCache INSTANCE = new EmptyDevicePolicyCache(); + + @Override + public boolean getScreenCaptureDisabled(int userHandle) { + return false; + } + } +} diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index d42fa996ceff49d8350dfc7b0937daf429883cfa..02e77df7a1ba8494f76f8ce194e2915f4de0feae 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3769,7 +3769,7 @@ public class DevicePolicyManager { /** * Called by an application that is administering the device to request that the storage system - * be encrypted. + * be encrypted. Does nothing if the caller is on a secondary user or a managed profile. *

* When multiple device administrators attempt to control device encryption, the most secure, * supported setting will always be used. If any device administrator requests device @@ -3791,10 +3791,13 @@ public class DevicePolicyManager { * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param encrypt true to request encryption, false to release any previous request - * @return the new request status (for all active admins) - will be one of - * {@link #ENCRYPTION_STATUS_UNSUPPORTED}, {@link #ENCRYPTION_STATUS_INACTIVE}, or - * {@link #ENCRYPTION_STATUS_ACTIVE}. This is the value of the requests; Use - * {@link #getStorageEncryptionStatus()} to query the actual device state. + * @return the new total request status (for all active admins), or {@link + * DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} if called for a non-system user. + * Will be one of {@link #ENCRYPTION_STATUS_UNSUPPORTED}, {@link + * #ENCRYPTION_STATUS_INACTIVE}, or {@link #ENCRYPTION_STATUS_ACTIVE}. This is the value + * of the requests; use {@link #getStorageEncryptionStatus()} to query the actual device + * state. + * * @throws SecurityException if {@code admin} is not an active administrator or does not use * {@link DeviceAdminInfo#USES_ENCRYPTED_STORAGE} */ @@ -9302,9 +9305,10 @@ public class DevicePolicyManager { * after calling this method. * *

The incoming target administrator must have the - * {@link DeviceAdminReceiver#SUPPORT_TRANSFER_OWNERSHIP_META_DATA} meta-data tag - * included in its corresponding receiver component with a value of {@code true}. - * Otherwise an {@link IllegalArgumentException} will be thrown. + * <support-transfer-ownership /> tag inside the + * <device-admin></device-admin> tags in the xml file referenced by + * {@link DeviceAdminReceiver#DEVICE_ADMIN_META_DATA}. Otherwise an + * {@link IllegalArgumentException} will be thrown. * * @param admin which {@link DeviceAdminReceiver} this request is associated with * @param target which {@link DeviceAdminReceiver} we want the new administrator to be diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index ebaf4648d80af16ff654fe794347bc7d9b840181..de9297897158ea750789dc70c6e809c94e9ad6ba 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -141,4 +141,10 @@ public abstract class DevicePolicyManagerInternal { * @return localized error message */ public abstract CharSequence getPrintingDisabledReasonForUser(@UserIdInt int userId); + + /** + * @return cached version of DPM policies that can be accessed without risking deadlocks. + * Do not call it directly. Use {@link DevicePolicyCache#getInstance()} instead. + */ + protected abstract DevicePolicyCache getDevicePolicyCache(); } diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java index af2fb713e1bc41b6f6c8420bdfcf17dfc6bc86ee..d16bc97cbc8750d4d97a3c1dbcdadf8d8db5d3f5 100644 --- a/core/java/android/app/servertransaction/ResumeActivityItem.java +++ b/core/java/android/app/servertransaction/ResumeActivityItem.java @@ -48,7 +48,8 @@ public class ResumeActivityItem extends ActivityLifecycleItem { public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); - client.handleResumeActivity(token, true /* clearHide */, mIsForward, "RESUME_ACTIVITY"); + client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward, + "RESUME_ACTIVITY"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java index 0a61fab2a8ea1ec5141d86e37d86f11b5120a419..8db38d36c57ea90923a0d5d96dabeeb4d223935c 100644 --- a/core/java/android/app/servertransaction/StopActivityItem.java +++ b/core/java/android/app/servertransaction/StopActivityItem.java @@ -39,7 +39,7 @@ public class StopActivityItem extends ActivityLifecycleItem { PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions, - "STOP_ACTIVITY_ITEM"); + true /* finalStateRequest */, "STOP_ACTIVITY_ITEM"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index 0e52b34715046008a967744f2933fb131a684a02..553c3ae15387ae64bbf96bd617424960f7ff4012 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. @@ -191,7 +194,7 @@ public class TransactionExecutor { mTransactionHandler.handleStartActivity(r, mPendingActions); break; case ON_RESUME: - mTransactionHandler.handleResumeActivity(r.token, false /* clearHide */, + mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */, r.isForward, "LIFECYCLER_RESUME_ACTIVITY"); break; case ON_PAUSE: @@ -201,7 +204,8 @@ public class TransactionExecutor { break; case ON_STOP: mTransactionHandler.handleStopActivity(r.token, false /* show */, - 0 /* configChanges */, mPendingActions, "LIFECYCLER_STOP_ACTIVITY"); + 0 /* configChanges */, mPendingActions, false /* finalStateRequest */, + "LIFECYCLER_STOP_ACTIVITY"); break; case ON_DESTROY: mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */, diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java index 7e66fd7a2ead9abdeb641dcbea33c94a62a7ceaa..01b13a28aed1f1ce3bfa7a0f0f207391986a5e5b 100644 --- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java +++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java @@ -26,7 +26,7 @@ import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP; import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE; import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; -import android.app.ActivityThread; +import android.app.ActivityThread.ActivityClientRecord; import android.util.IntArray; import com.android.internal.annotations.VisibleForTesting; @@ -124,7 +124,7 @@ public class TransactionExecutorHelper { * {@link ActivityLifecycleItem#UNDEFINED} if there is not path. */ @VisibleForTesting - public int getClosestPreExecutionState(ActivityThread.ActivityClientRecord r, + public int getClosestPreExecutionState(ActivityClientRecord r, int postExecutionState) { switch (postExecutionState) { case UNDEFINED: @@ -147,7 +147,7 @@ public class TransactionExecutorHelper { * were provided or there is not path. */ @VisibleForTesting - public int getClosestOfStates(ActivityThread.ActivityClientRecord r, int[] finalStates) { + public int getClosestOfStates(ActivityClientRecord r, int[] finalStates) { if (finalStates == null || finalStates.length == 0) { return UNDEFINED; } @@ -168,6 +168,27 @@ public class TransactionExecutorHelper { return closestState; } + /** Get the lifecycle state request to match the current state in the end of a transaction. */ + public static ActivityLifecycleItem getLifecycleRequestForCurrentState(ActivityClientRecord r) { + final int prevState = r.getLifecycleState(); + final ActivityLifecycleItem lifecycleItem; + switch (prevState) { + // TODO(lifecycler): Extend to support all possible states. + case ON_PAUSE: + lifecycleItem = PauseActivityItem.obtain(); + break; + case ON_STOP: + lifecycleItem = StopActivityItem.obtain(r.isVisibleFromServer(), + 0 /* configChanges */); + break; + default: + lifecycleItem = ResumeActivityItem.obtain(false /* isForward */); + break; + } + + return lifecycleItem; + } + /** * Check if there is a destruction involved in the path. We want to avoid a lifecycle sequence * that involves destruction and recreation if there is another path. diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl index 20ec75a36ad3e7e834c7405cdf3aaaaf837defa2..74e3c3ee4c81661cc56cd521e25c5129cb9d8287 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 4f3cd63841eb3f598452bf1cbd40db075aae7ea4..67a72ec33fd82eafeee92d705e3999d99f7b4c55 100644 --- a/core/java/android/app/slice/SliceManager.java +++ b/core/java/android/app/slice/SliceManager.java @@ -183,6 +183,18 @@ public class SliceManager { } } + /** + * Get the list of currently pinned slices for this app. + * @see SliceProvider#onSlicePinned + */ + public @NonNull List 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. *

@@ -261,7 +273,8 @@ public class SliceManager { */ public @Nullable Uri mapIntentToUri(@NonNull Intent intent) { Preconditions.checkNotNull(intent, "intent"); - Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null, + Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null + || intent.getData() != null, "Slice intent must be explicit %s", intent); ContentResolver resolver = mContext.getContentResolver(); @@ -325,7 +338,8 @@ public class SliceManager { public @Nullable Slice bindSlice(@NonNull Intent intent, @NonNull List supportedSpecs) { Preconditions.checkNotNull(intent, "intent"); - Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null, + Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null + || intent.getData() != null, "Slice intent must be explicit %s", intent); ContentResolver resolver = mContext.getContentResolver(); diff --git a/core/java/android/app/slice/SliceMetrics.java b/core/java/android/app/slice/SliceMetrics.java new file mode 100644 index 0000000000000000000000000000000000000000..a7069bc107d450240d091acd6ca5c4b538cac68d --- /dev/null +++ b/core/java/android/app/slice/SliceMetrics.java @@ -0,0 +1,63 @@ +/* + * 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.app.slice; + +import android.annotation.NonNull; +import android.content.Context; +import android.net.Uri; + +import com.android.internal.logging.MetricsLogger; + +/** + * Metrics interface for slices. + * + * This is called by SliceView, so Slice develoers should + * not need to reference this class. + * + * @see androidx.slice.widget.SliceView + */ +public class SliceMetrics { + + private static final String TAG = "SliceMetrics"; + private MetricsLogger mMetricsLogger; + + /** + * An object to be used throughout the life of a slice to register events. + */ + public SliceMetrics(@NonNull Context context, @NonNull Uri uri) { + mMetricsLogger = new MetricsLogger(); + } + + /** + * To be called whenever the slice becomes visible to the user. + */ + public void logVisible() { + } + + /** + * To be called whenever the slice becomes invisible to the user. + */ + public void logHidden() { + } + + /** + * To be called whenever the use interacts with a slice. + *@param subSlice The URI of the sub-slice that is the subject of the interaction. + */ + public void logTouch(@NonNull Uri subSlice) { + } +} diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index df32fb9c2e75fd990b92e0bf7148e6a09c2965e8..aa2cf46891d84916399352b97bc01e6e907cb911 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -16,7 +16,6 @@ package android.app.slice; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.PendingIntent; import android.content.ComponentName; import android.content.ContentProvider; @@ -35,7 +34,6 @@ import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; -import android.os.Looper; import android.os.Process; import android.os.StrictMode; import android.os.StrictMode.ThreadPolicy; @@ -46,7 +44,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.concurrent.CountDownLatch; /** * A SliceProvider allows an app to provide content to be displayed in system spaces. This content @@ -163,18 +160,10 @@ public abstract class SliceProvider extends ContentProvider { private static final boolean DEBUG = false; - private String mBindingPkg; - private SliceManager mSliceManager; + private static final long SLICE_BIND_ANR = 2000; - /** - * Return the package name of the caller that initiated the binding request - * currently happening. The returned package will have been - * verified to belong to the calling UID. Returns {@code null} if not - * currently performing an {@link #onBindSlice(Uri, List)}. - */ - public final @Nullable String getBindingPackage() { - return mBindingPkg; - } + private String mCallback; + private SliceManager mSliceManager; @Override public void attachInfo(Context context, ProviderInfo info) { @@ -183,12 +172,12 @@ public abstract class SliceProvider extends ContentProvider { } /** - * Implemented to create a slice. Will be called on the main thread. + * Implemented to create a slice. *

* onBindSlice should return as quickly as possible so that the UI tied * to this slice can be responsive. No network or other IO will be allowed * during onBindSlice. Any loading that needs to be done should happen - * off the main thread with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)} + * in the background with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)} * when the app is ready to provide the complete data in onBindSlice. *

* The slice returned should have a spec that is compatible with one of @@ -381,55 +370,32 @@ public abstract class SliceProvider extends ContentProvider { } private Collection handleGetDescendants(Uri uri) { - if (Looper.myLooper() == Looper.getMainLooper()) { + mCallback = "onGetSliceDescendants"; + Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR); + try { return onGetSliceDescendants(uri); - } else { - CountDownLatch latch = new CountDownLatch(1); - Collection[] output = new Collection[1]; - Handler.getMain().post(() -> { - output[0] = onGetSliceDescendants(uri); - latch.countDown(); - }); - try { - latch.await(); - return output[0]; - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + } finally { + Handler.getMain().removeCallbacks(mAnr); } } private void handlePinSlice(Uri sliceUri) { - if (Looper.myLooper() == Looper.getMainLooper()) { + mCallback = "onSlicePinned"; + Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR); + try { onSlicePinned(sliceUri); - } else { - CountDownLatch latch = new CountDownLatch(1); - Handler.getMain().post(() -> { - onSlicePinned(sliceUri); - latch.countDown(); - }); - try { - latch.await(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + } finally { + Handler.getMain().removeCallbacks(mAnr); } } private void handleUnpinSlice(Uri sliceUri) { - if (Looper.myLooper() == Looper.getMainLooper()) { + mCallback = "onSliceUnpinned"; + Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR); + try { onSliceUnpinned(sliceUri); - } else { - CountDownLatch latch = new CountDownLatch(1); - Handler.getMain().post(() -> { - onSliceUnpinned(sliceUri); - latch.countDown(); - }); - try { - latch.await(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + } finally { + Handler.getMain().removeCallbacks(mAnr); } } @@ -447,21 +413,12 @@ public abstract class SliceProvider extends ContentProvider { return createPermissionSlice(getContext(), sliceUri, pkg); } } - if (Looper.myLooper() == Looper.getMainLooper()) { - return onBindSliceStrict(sliceUri, supportedSpecs, pkg); - } else { - CountDownLatch latch = new CountDownLatch(1); - Slice[] output = new Slice[1]; - Handler.getMain().post(() -> { - output[0] = onBindSliceStrict(sliceUri, supportedSpecs, pkg); - latch.countDown(); - }); - try { - latch.await(); - return output[0]; - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + mCallback = "onBindSlice"; + Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR); + try { + return onBindSliceStrict(sliceUri, supportedSpecs); + } finally { + Handler.getMain().removeCallbacks(mAnr); } } @@ -513,19 +470,21 @@ public abstract class SliceProvider extends ContentProvider { } } - private Slice onBindSliceStrict(Uri sliceUri, List supportedSpecs, - String callingPackage) { + private Slice onBindSliceStrict(Uri sliceUri, List supportedSpecs) { ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); try { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectAll() .penaltyDeath() .build()); - mBindingPkg = callingPackage; return onBindSlice(sliceUri, supportedSpecs); } finally { - mBindingPkg = null; StrictMode.setThreadPolicy(oldPolicy); } } + + private final Runnable mAnr = () -> { + Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT); + Log.wtf(TAG, "Timed out while handling slice callback " + mCallback); + }; } diff --git a/core/java/android/app/slice/SliceSpec.java b/core/java/android/app/slice/SliceSpec.java index 8cc0384c10072db640ce678cee69df18dcc89539..03ffe6df88ce1523b47e3e95b3fcfe1434d7bb1e 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/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index fff1a00c585ef9365c3ce89c4807e57391aef2b8..d52bd37641014a933a5b89079fcf0f542fc78ca3 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -16,6 +16,7 @@ package android.app.usage; +import android.app.PendingIntent; import android.app.usage.UsageEvents; import android.content.pm.ParceledListSlice; @@ -43,4 +44,7 @@ interface IUsageStatsManager { void setAppStandbyBucket(String packageName, int bucket, int userId); ParceledListSlice getAppStandbyBuckets(String callingPackage, int userId); void setAppStandbyBuckets(in ParceledListSlice appBuckets, int userId); + void registerAppUsageObserver(int observerId, in String[] packages, long timeLimitMs, + in PendingIntent callback, String callingPackage); + void unregisterAppUsageObserver(int observerId, String callingPackage); } diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index 521ab4edc4c561212491595a7b9a1cca072a0fc2..8550ac0f32cd4c79a13280c921743038180808e7 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -81,6 +81,7 @@ public final class UsageEvents implements Parcelable { * An event type denoting that a package was interacted with in some way by the system. * @hide */ + @SystemApi public static final int SYSTEM_INTERACTION = 6; /** @@ -109,12 +110,20 @@ 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. + * An event type denoting a change in App Standby Bucket. The new bucket can be + * retrieved by calling {@link #getStandbyBucket()}. + * + * @see UsageStatsManager#getAppStandbyBucket() + */ + public static final int STANDBY_BUCKET_CHANGED = 11; + + /** + * An event type denoting that an app posted an interruptive notification. Visual and + * audible interruptions are included. * @hide */ @SystemApi - public static final int STANDBY_BUCKET_CHANGED = 11; + public static final int NOTIFICATION_INTERRUPTION = 12; /** @hide */ public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0; @@ -188,6 +197,14 @@ public final class UsageEvents implements Parcelable { */ public int mBucketAndReason; + /** + * The id of the {@link android.app.NotificationChannel} to which an interruptive + * notification was posted. + * Only present for {@link #NOTIFICATION_INTERRUPTION} event types. + * {@hide} + */ + public String mNotificationChannelId; + /** @hide */ @EventFlags public int mFlags; @@ -208,6 +225,7 @@ public final class UsageEvents implements Parcelable { mContentAnnotations = orig.mContentAnnotations; mFlags = orig.mFlags; mBucketAndReason = orig.mBucketAndReason; + mNotificationChannelId = orig.mNotificationChannelId; } /** @@ -237,8 +255,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; @@ -266,9 +287,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; } @@ -285,6 +305,16 @@ public final class UsageEvents implements Parcelable { return mBucketAndReason & 0x0000FFFF; } + /** + * Returns the ID of the {@link android.app.NotificationChannel} for this event if the + * event is of type {@link #NOTIFICATION_INTERRUPTION}, otherwise it returns null; + * @hide + */ + @SystemApi + public String getNotificationChannelId() { + return mNotificationChannelId; + } + /** @hide */ public Event getObfuscatedIfInstantApp() { if ((mFlags & FLAG_IS_PACKAGE_INSTANT_APP) == 0) { @@ -444,6 +474,9 @@ public final class UsageEvents implements Parcelable { case Event.STANDBY_BUCKET_CHANGED: p.writeInt(event.mBucketAndReason); break; + case Event.NOTIFICATION_INTERRUPTION: + p.writeString(event.mNotificationChannelId); + break; } } @@ -473,6 +506,7 @@ public final class UsageEvents implements Parcelable { eventOut.mAction = null; eventOut.mContentType = null; eventOut.mContentAnnotations = null; + eventOut.mNotificationChannelId = null; switch (eventOut.mEventType) { case Event.CONFIGURATION_CHANGE: @@ -490,6 +524,9 @@ public final class UsageEvents implements Parcelable { case Event.STANDBY_BUCKET_CHANGED: eventOut.mBucketAndReason = p.readInt(); break; + case Event.NOTIFICATION_INTERRUPTION: + eventOut.mNotificationChannelId = p.readString(); + break; } } diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 5f9fa43203dad9718fe2606539520c9848e42795..1c3845802dfd194e07feb002dd873044ae51fdcd 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.app.PendingIntent; import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.RemoteException; @@ -32,6 +33,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; /** * Provides access to device usage history and statistics. Usage data is aggregated into @@ -105,25 +107,35 @@ public final class UsageStatsManager { public static final int STANDBY_BUCKET_EXEMPTED = 5; /** - * The app was used very recently, currently in use or likely to be used very soon. + * The app was used very recently, currently in use or likely to be used very soon. Standby + * bucket values that are ≤ {@link #STANDBY_BUCKET_ACTIVE} will not be throttled by the + * system while they are in this bucket. Buckets > {@link #STANDBY_BUCKET_ACTIVE} will most + * likely be restricted in some way. For instance, jobs and alarms may be deferred. * @see #getAppStandbyBucket() */ public static final int STANDBY_BUCKET_ACTIVE = 10; /** - * The app was used recently and/or likely to be used in the next few hours. + * The app was used recently and/or likely to be used in the next few hours. Restrictions will + * apply to these apps, such as deferral of jobs and alarms. * @see #getAppStandbyBucket() */ public static final int STANDBY_BUCKET_WORKING_SET = 20; /** * The app was used in the last few days and/or likely to be used in the next few days. + * Restrictions will apply to these apps, such as deferral of jobs and alarms. The delays may be + * greater than for apps in higher buckets (lower bucket value). Bucket values > + * {@link #STANDBY_BUCKET_FREQUENT} may additionally have network access limited. * @see #getAppStandbyBucket() */ public static final int STANDBY_BUCKET_FREQUENT = 30; /** * The app has not be used for several days and/or is unlikely to be used for several days. + * Apps in this bucket will have the most restrictions, including network restrictions, except + * during certain short periods (at a minimum, once a day) when they are allowed to execute + * jobs, access the network, etc. * @see #getAppStandbyBucket() */ public static final int STANDBY_BUCKET_RARE = 40; @@ -179,6 +191,31 @@ public final class UsageStatsManager { @Retention(RetentionPolicy.SOURCE) public @interface StandbyBuckets {} + /** + * Observer id of the registered observer for the group of packages that reached the usage + * time limit. Included as an extra in the PendingIntent that was registered. + * @hide + */ + @SystemApi + public static final String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID"; + + /** + * Original time limit in milliseconds specified by the registered observer for the group of + * packages that reached the usage time limit. Included as an extra in the PendingIntent that + * was registered. + * @hide + */ + @SystemApi + public static final String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT"; + + /** + * Actual usage time in milliseconds for the group of packages that reached the specified time + * limit. Included as an extra in the PendingIntent that was registered. + * @hide + */ + @SystemApi + public static final String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED"; + private static final UsageEvents sEmptyResults = new UsageEvents(); private final Context mContext; @@ -366,11 +403,19 @@ public final class UsageStatsManager { /** * Returns the current standby bucket of the calling app. The system determines the standby * state of the app based on app usage patterns. Standby buckets determine how much an app will - * be restricted from running background tasks such as jobs, alarms and certain PendingIntent - * callbacks. + * be restricted from running background tasks such as jobs and alarms. *

Restrictions increase progressively from {@link #STANDBY_BUCKET_ACTIVE} to * {@link #STANDBY_BUCKET_RARE}, with {@link #STANDBY_BUCKET_ACTIVE} being the least * restrictive. The battery level of the device might also affect the restrictions. + *

Apps in buckets ≤ {@link #STANDBY_BUCKET_ACTIVE} have no standby restrictions imposed. + * Apps in buckets > {@link #STANDBY_BUCKET_FREQUENT} may have network access restricted when + * running in the background. + *

The standby state of an app can change at any time either due to a user interaction or a + * system interaction or some algorithm determining that the app can be restricted for a period + * of time before the user has a need for it. + *

You can also query the recent history of standby bucket changes by calling + * {@link #queryEventsForSelf(long, long)} and searching for + * {@link UsageEvents.Event#STANDBY_BUCKET_CHANGED}. * * @return the current standby bucket of the calling app. One of STANDBY_BUCKET_* constants. */ @@ -470,6 +515,53 @@ public final class UsageStatsManager { } } + /** + * @hide + * Register an app usage limit observer that receives a callback on the provided intent when + * the sum of usages of apps in the packages array exceeds the timeLimit specified. The + * observer will automatically be unregistered when the time limit is reached and the intent + * is delivered. + * @param observerId A unique id associated with the group of apps to be monitored. There can + * be multiple groups with common packages and different time limits. + * @param packages The list of packages to observe for foreground activity time. Must include + * at least one package. + * @param timeLimit The total time the set of apps can be in the foreground before the + * callbackIntent is delivered. Must be greater than 0. + * @param timeUnit The unit for time specified in timeLimit. + * @param callbackIntent The PendingIntent that will be dispatched when the time limit is + * exceeded by the group of apps. The delivered Intent will also contain + * the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and + * {@link #EXTRA_TIME_USED}. + * @throws SecurityException if the caller doesn't have the PACKAGE_USAGE_STATS permission. + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) + public void registerAppUsageObserver(int observerId, String[] packages, long timeLimit, + TimeUnit timeUnit, PendingIntent callbackIntent) { + try { + mService.registerAppUsageObserver(observerId, packages, timeUnit.toMillis(timeLimit), + callbackIntent, mContext.getOpPackageName()); + } catch (RemoteException e) { + } + } + + /** + * @hide + * Unregister the app usage observer specified by the observerId. This will only apply to any + * observer registered by this application. Unregistering an observer that was already + * unregistered or never registered will have no effect. + * @param observerId The id of the observer that was previously registered. + * @throws SecurityException if the caller doesn't have the PACKAGE_USAGE_STATS permission. + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) + public void unregisterAppUsageObserver(int observerId) { + try { + mService.unregisterAppUsageObserver(observerId, mContext.getOpPackageName()); + } catch (RemoteException e) { + } + } + /** @hide */ public static String reasonToString(int standbyReason) { StringBuilder sb = new StringBuilder(); diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index b62b1ee0492b0a22d4c447110076f28e41eb15b9..09ced2648de1acff210fa0dc5251baf219102945 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -58,6 +58,16 @@ public abstract class UsageStatsManagerInternal { */ public abstract void reportConfigurationChange(Configuration config, @UserIdInt int userId); + /** + * Reports that an application has posted an interruptive notification. + * + * @param packageName The package name of the app that posted the notification + * @param channelId The ID of the NotificationChannel to which the notification was posted + * @param userId The user in which the notification was posted + */ + public abstract void reportInterruptiveNotification(String packageName, String channelId, + @UserIdInt int userId); + /** * Reports that an action equivalent to a ShortcutInfo is taken by the user. * diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index e736f34eea117c37513e71d25b04cf7d3ae822d1..20248b90d1e931581b5defcdbfb790b8d20756b1 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -35,7 +35,6 @@ import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.os.Bundle; import android.os.Handler; -import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.util.DisplayMetrics; @@ -680,11 +679,13 @@ public class AppWidgetManager { } /** - * Updates the info for the supplied AppWidget provider. + * Updates the info for the supplied AppWidget provider. Apps can use this to change the default + * behavior of the widget based on the state of the app (for e.g., if the user is logged in + * or not). Calling this API completely replaces the previous definition. * *

* The manifest entry of the provider should contain an additional meta-data tag similar to - * {@link #META_DATA_APPWIDGET_PROVIDER} which should point to any additional definitions for + * {@link #META_DATA_APPWIDGET_PROVIDER} which should point to any alternative definitions for * the provider. * *

@@ -1186,6 +1187,11 @@ public class AppWidgetManager { * calls this API multiple times in a row. It may ignore the previous requests, * for example. * + *

Launcher will not show the configuration activity associated with the provider in this + * case. The app could either show the configuration activity as a response to the callback, + * or show if before calling the API (various configurations can be encapsulated in + * {@code successCallback} to avoid persisting them before the widgetId is known). + * * @param provider The {@link ComponentName} for the {@link * android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget. * @param extras In not null, this is passed to the launcher app. For eg {@link diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 75ce4fbb60c7c9f5d07dc44b8a1ea07fefef742b..6dd85caad628d7fa244907cf379de11bc8e4cd9a 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -16,6 +16,7 @@ package android.appwidget; +import android.annotation.IntDef; import android.annotation.NonNull; import android.app.PendingIntent; import android.content.ComponentName; @@ -32,6 +33,9 @@ import android.os.UserHandle; import android.util.DisplayMetrics; import android.util.TypedValue; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Describes the meta data for an installed AppWidget provider. The fields in this class * correspond to the fields in the <appwidget-provider> xml tag. @@ -55,6 +59,14 @@ public class AppWidgetProviderInfo implements Parcelable { */ public static final int RESIZE_BOTH = RESIZE_HORIZONTAL | RESIZE_VERTICAL; + /** @hide */ + @IntDef(flag = true, prefix = { "FLAG_" }, value = { + RESIZE_HORIZONTAL, + RESIZE_VERTICAL, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ResizeModeFlags {} + /** * Indicates that the widget can be displayed on the home screen. This is the default value. */ @@ -70,6 +82,15 @@ public class AppWidgetProviderInfo implements Parcelable { */ public static final int WIDGET_CATEGORY_SEARCHBOX = 4; + /** @hide */ + @IntDef(flag = true, prefix = { "FLAG_" }, value = { + WIDGET_CATEGORY_HOME_SCREEN, + WIDGET_CATEGORY_KEYGUARD, + WIDGET_CATEGORY_SEARCHBOX, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CategoryFlags {} + /** * The widget can be reconfigured anytime after it is bound by starting the * {@link #configure} activity. @@ -87,6 +108,14 @@ public class AppWidgetProviderInfo implements Parcelable { */ public static final int WIDGET_FEATURE_HIDE_FROM_PICKER = 2; + /** @hide */ + @IntDef(flag = true, prefix = { "FLAG_" }, value = { + WIDGET_FEATURE_RECONFIGURABLE, + WIDGET_FEATURE_HIDE_FROM_PICKER, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FeatureFlags {} + /** * Identity of this AppWidget component. This component should be a {@link * android.content.BroadcastReceiver}, and it will be sent the AppWidget intents @@ -215,6 +244,7 @@ public class AppWidgetProviderInfo implements Parcelable { *

This field corresponds to the android:resizeMode attribute in * the AppWidget meta-data file. */ + @ResizeModeFlags public int resizeMode; /** @@ -226,6 +256,7 @@ public class AppWidgetProviderInfo implements Parcelable { *

This field corresponds to the widgetCategory attribute in * the AppWidget meta-data file. */ + @CategoryFlags public int widgetCategory; /** @@ -235,6 +266,7 @@ public class AppWidgetProviderInfo implements Parcelable { * @see #WIDGET_FEATURE_RECONFIGURABLE * @see #WIDGET_FEATURE_HIDE_FROM_PICKER */ + @FeatureFlags public int widgetFeatures; /** @hide */ diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index ee667c2207795a3db54b481039057fa00d97da0c..b9e80e4067997ba740e627133bcc428450fc8ced 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -680,6 +680,10 @@ public final class BluetoothAdapter { if (!getLeAccess()) { return null; } + if (!isMultipleAdvertisementSupported()) { + Log.e(TAG, "Bluetooth LE advertising not supported"); + return null; + } synchronized (mLock) { if (sBluetoothLeAdvertiser == null) { sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java index 5a1216b79b8295aa1f7906a3984a7176f1c195ad..b528e397906f5252d314801d84780247eaf16023 100644 --- a/core/java/android/content/AbstractThreadedSyncAdapter.java +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -16,9 +16,14 @@ package android.content; +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + import android.accounts.Account; +import android.annotation.MainThread; +import android.annotation.NonNull; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; @@ -167,9 +172,10 @@ public abstract class AbstractThreadedSyncAdapter { private class ISyncAdapterImpl extends ISyncAdapter.Stub { @Override - public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb) - throws RemoteException { - cb.onUnsyncableAccountDone(AbstractThreadedSyncAdapter.this.onUnsyncableAccount()); + public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb) { + Handler.getMain().sendMessage(obtainMessage( + AbstractThreadedSyncAdapter::handleOnUnsyncableAccount, + AbstractThreadedSyncAdapter.this, cb)); } @Override @@ -380,6 +386,27 @@ public abstract class AbstractThreadedSyncAdapter { return mISyncAdapterImpl.asBinder(); } + /** + * Handle a call of onUnsyncableAccount. + * + * @param cb The callback to report the return value to + */ + private void handleOnUnsyncableAccount(@NonNull ISyncAdapterUnsyncableAccountCallback cb) { + boolean doSync; + try { + doSync = onUnsyncableAccount(); + } catch (RuntimeException e) { + Log.e(TAG, "Exception while calling onUnsyncableAccount, assuming 'true'", e); + doSync = true; + } + + try { + cb.onUnsyncableAccountDone(doSync); + } catch (RemoteException e) { + Log.e(TAG, "Could not report result of onUnsyncableAccount", e); + } + } + /** * Allows to defer syncing until all accounts are properly set up. * @@ -393,9 +420,16 @@ public abstract class AbstractThreadedSyncAdapter { * *

This might be called on a different service connection as {@link #onPerformSync}. * + *

The system expects this method to immediately return. If the call stalls the system + * behaves as if this method returned {@code true}. If it is required to perform a longer task + * (such as interacting with the user), return {@code false} and proceed in a difference + * context, such as an {@link android.app.Activity}, or foreground service. The sync can then be + * rescheduled once the account becomes syncable. + * * @return If {@code false} syncing is deferred. Returns {@code true} by default, i.e. by * default syncing starts immediately. */ + @MainThread public boolean onUnsyncableAccount() { return true; } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 10331d49dd36c58ec71b78dc80c7ea17e77e6227..ce7d3af8404ade965f1d2b4b4c7badf577eb1b06 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -2142,21 +2142,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 diff --git a/core/java/android/content/SyncResult.java b/core/java/android/content/SyncResult.java index 4f86af985dc6359477b36d1b6e7602cc3798d2f2..f67d7f53d1c17a0f2adfd8a6e715641723d89a59 100644 --- a/core/java/android/content/SyncResult.java +++ b/core/java/android/content/SyncResult.java @@ -79,7 +79,17 @@ public final class SyncResult implements Parcelable { /** * Used to indicate to the SyncManager that future sync requests that match the request's - * Account and authority should be delayed at least this many seconds. + * Account and authority should be delayed until a time in seconds since Java epoch. + * + *

For example, if you want to delay the next sync for at least 5 minutes, then: + *

+     * result.delayUntil = (System.currentTimeMillis() / 1000) + 5 * 60;
+     * 
+ * + *

By default, when a sync fails, the system retries later with an exponential back-off + * with the system default initial delay time, which always wins over {@link #delayUntil} -- + * i.e. if the system back-off time is larger than {@link #delayUntil}, {@link #delayUntil} + * will essentially be ignored. */ public long delayUntil; diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 15bfdd075ba885e9e118a7244556a607901ac15f..593b12be843e128afb9c8c3fb7fc988f6ad747d6 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -1209,7 +1209,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/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index b4a7eec0fb4caa6ff119b8a1310add3e9e6c03a6..21ede165efaf887bf5e8dcc35bc6d62103b74d4e 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -1429,6 +1429,10 @@ public class LauncherApps { * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a * different request type. * + *

Launcher should not show any configuration activity associated with the provider, and + * assume that the widget is already fully configured. Upon accepting the widget, it should + * pass the widgetId in {@link #accept(Bundle)}. + * * @return requested {@link AppWidgetProviderInfo} when a request is of the * {@link #REQUEST_TYPE_APPWIDGET} type. Null otherwise. */ diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index bd7961fffca8dfe26a75fcbd1a212ff95a1ff8a0..3536eea854232cd5bf61b25675eac9bb475571a0 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4182,6 +4182,12 @@ public abstract class PackageManager { */ public abstract ResolveInfo resolveService(Intent intent, @ResolveInfoFlags int flags); + /** + * @hide + */ + public abstract ResolveInfo resolveServiceAsUser(Intent intent, @ResolveInfoFlags int flags, + @UserIdInt int userId); + /** * Retrieve all services that can match the given intent. * diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 5b3d3e595a91c8d670af0aef4813558e4114f223..dff51f77788ee95ee02495811392b1b71ee9b157 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 5d5a9782884a7ee87f9821e0f3366053f9a87939..bc7540fabc193d22db7fbd2f0095c11385b29588 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/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 8502fc413c0592625a476fabd776caa65d52a840..390b83fe10cfd68b2e2b0dfc3c10d483c6a4b572 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -28,7 +28,9 @@ import android.util.Rational; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** *

The properties describing a @@ -450,23 +452,20 @@ public final class CameraCharacteristics extends CameraMetadataA camera device is a logical camera if it has * REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability. If the camera device - * doesn't have the capability, the return value will be an empty list.

+ * doesn't have the capability, the return value will be an empty set.

* - *

The list returned is not modifiable, so any attempts to modify it will throw + *

The set returned is not modifiable, so any attempts to modify it will throw * a {@code UnsupportedOperationException}.

* - *

Each physical camera id is only listed once in the list. The order of the keys - * is undefined.

- * - * @return List of physical camera ids for this logical camera device. + * @return Set of physical camera ids for this logical camera device. */ @NonNull - public List getPhysicalCameraIds() { + public Set getPhysicalCameraIds() { int[] availableCapabilities = get(REQUEST_AVAILABLE_CAPABILITIES); if (availableCapabilities == null) { throw new AssertionError("android.request.availableCapabilities must be non-null " @@ -475,7 +474,7 @@ public final class CameraCharacteristics extends CameraMetadata(Arrays.asList(physicalCameraIdArray))); } /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ @@ -1243,7 +1242,7 @@ public final class CameraCharacteristics extends CameraMetadata(0.03, 0, 0).

*

To transform a pixel coordinates between two cameras facing the same direction, first - * the source camera {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for. Then the source + * the source camera {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} must be corrected for. Then the source * camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs to be applied, followed by the * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the source camera, the translation of the source camera * relative to the destination camera, the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination @@ -1257,10 +1256,10 @@ public final class CameraCharacteristics extends CameraMetadataUnits: Meters

*

Optional - This value may be {@code null} on some devices.

* + * @see CameraCharacteristics#LENS_DISTORTION * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION * @see CameraCharacteristics#LENS_POSE_REFERENCE * @see CameraCharacteristics#LENS_POSE_ROTATION - * @see CameraCharacteristics#LENS_RADIAL_DISTORTION */ @PublicKey public static final Key LENS_POSE_TRANSLATION = @@ -1306,7 +1305,7 @@ public final class CameraCharacteristics extends CameraMetadata(0,0) is the top-left of the * preCorrectionActiveArraySize rectangle. Once the pose and * intrinsic calibration transforms have been applied to a - * world point, then the {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} + * world point, then the {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} * transform needs to be applied, and the result adjusted to * be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate * system (where (0, 0) is the top-left of the @@ -1319,9 +1318,9 @@ public final class CameraCharacteristics extends CameraMetadata *

Optional - This value may be {@code null} on some devices.

* + * @see CameraCharacteristics#LENS_DISTORTION * @see CameraCharacteristics#LENS_POSE_ROTATION * @see CameraCharacteristics#LENS_POSE_TRANSLATION - * @see CameraCharacteristics#LENS_RADIAL_DISTORTION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @@ -1363,7 +1362,14 @@ public final class CameraCharacteristics extends CameraMetadataOptional - This value may be {@code null} on some devices.

* * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION + * @deprecated + *

This field was inconsistently defined in terms of its + * normalization. Use {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} instead.

+ * + * @see CameraCharacteristics#LENS_DISTORTION + */ + @Deprecated @PublicKey public static final Key LENS_RADIAL_DISTORTION = new Key("android.lens.radialDistortion", float[].class); @@ -1387,6 +1393,46 @@ public final class CameraCharacteristics extends CameraMetadata LENS_POSE_REFERENCE = new Key("android.lens.poseReference", int.class); + /** + *

The correction coefficients to correct for this camera device's + * radial and tangential lens distortion.

+ *

Replaces the deprecated {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} field, which was + * inconsistently defined.

+ *

Three radial distortion coefficients [kappa_1, kappa_2, + * kappa_3] and two tangential distortion coefficients + * [kappa_4, kappa_5] that can be used to correct the + * lens's geometric distortion with the mapping equations:

+ *
 x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) +
+     *        kappa_4 * (2 * x_i * y_i) + kappa_5 * ( r^2 + 2 * x_i^2 )
+     *  y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) +
+     *        kappa_5 * (2 * x_i * y_i) + kappa_4 * ( r^2 + 2 * y_i^2 )
+     * 
+ *

Here, [x_c, y_c] are the coordinates to sample in the + * input image that correspond to the pixel values in the + * corrected image at the coordinate [x_i, y_i]:

+ *
 correctedImage(x_i, y_i) = sample_at(x_c, y_c, inputImage)
+     * 
+ *

The pixel coordinates are defined in a coordinate system + * related to the {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} + * calibration fields; see that entry for details of the mapping stages. + * Both [x_i, y_i] and [x_c, y_c] + * have (0,0) at the lens optical center [c_x, c_y], and + * the range of the coordinates depends on the focal length + * terms of the intrinsic calibration.

+ *

Finally, r represents the radial distance from the + * optical center, r^2 = x_i^2 + y_i^2.

+ *

The distortion model used is the Brown-Conrady model.

+ *

Units: + * Unitless coefficients.

+ *

Optional - This value may be {@code null} on some devices.

+ * + * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION + * @see CameraCharacteristics#LENS_RADIAL_DISTORTION + */ + @PublicKey + public static final Key LENS_DISTORTION = + new Key("android.lens.distortion", float[].class); + /** *

List of noise reduction modes for {@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode} that are supported * by this camera device.

@@ -1419,6 +1465,8 @@ public final class CameraCharacteristics extends CameraMetadata *

Optional - This value may be {@code null} on some devices.

* @deprecated + *

Not used in HALv3 or newer; replaced by better partials mechanism

+ * @hide */ @Deprecated @@ -1809,6 +1857,8 @@ public final class CameraCharacteristics extends CameraMetadataWhen set to YUV_420_888, application can access the YUV420 data directly.

*

Optional - This value may be {@code null} on some devices.

* @deprecated + *

Not used in HALv3 or newer

+ * @hide */ @Deprecated @@ -1829,6 +1879,8 @@ public final class CameraCharacteristics extends CameraMetadata *

Optional - This value may be {@code null} on some devices.

* @deprecated + *

Not used in HALv3 or newer

+ * @hide */ @Deprecated @@ -1845,6 +1897,8 @@ public final class CameraCharacteristics extends CameraMetadataNot used in HALv3 or newer

+ * @hide */ @Deprecated @@ -1884,6 +1938,8 @@ public final class CameraCharacteristics extends CameraMetadataUnits: Nanoseconds

*

Optional - This value may be {@code null} on some devices.

* @deprecated + *

Not used in HALv3 or newer

+ * @hide */ @Deprecated @@ -1906,6 +1962,8 @@ public final class CameraCharacteristics extends CameraMetadata *

Optional - This value may be {@code null} on some devices.

* @deprecated + *

Not used in HALv3 or newer

+ * @hide */ @Deprecated @@ -2545,7 +2603,7 @@ public final class CameraCharacteristics extends CameraMetadata *

The currently supported fields that correct for geometric distortion are:

*
    - *
  1. {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}.
  2. + *
  3. {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}.
  4. *
*

If all of the geometric distortion fields are no-ops, this rectangle will be the same * as the post-distortion-corrected rectangle given in @@ -2558,7 +2616,7 @@ public final class CameraCharacteristics extends CameraMetadataUnits: Pixel coordinates on the image sensor

*

This key is available on all devices.

* - * @see CameraCharacteristics#LENS_RADIAL_DISTORTION + * @see CameraCharacteristics#LENS_DISTORTION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 52aefcc4830451fac642b70cf8dd9c55aae119b3..7669c018acd1583fc93cdda91cc5ef6ae6380c8b 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -684,7 +684,7 @@ public abstract class CameraMetadata { *
  • {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}
  • *
  • {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}
  • *
  • {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
  • - *
  • {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}
  • + *
  • {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}
  • * * *
  • The {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} entry is listed by this device.
  • @@ -702,12 +702,12 @@ public abstract class CameraMetadata { * rate, including depth stall time.

    * * @see CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE + * @see CameraCharacteristics#LENS_DISTORTION * @see CameraCharacteristics#LENS_FACING * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION * @see CameraCharacteristics#LENS_POSE_REFERENCE * @see CameraCharacteristics#LENS_POSE_ROTATION * @see CameraCharacteristics#LENS_POSE_TRANSLATION - * @see CameraCharacteristics#LENS_RADIAL_DISTORTION * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES */ public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8; @@ -826,7 +826,7 @@ public abstract class CameraMetadata { *
  • {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}
  • *
  • {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}
  • *
  • {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
  • - *
  • {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}
  • + *
  • {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}
  • * * *
  • The SENSOR_INFO_TIMESTAMP_SOURCE of the logical device and physical devices must be @@ -852,11 +852,11 @@ public abstract class CameraMetadata { * not slow down the frame rate of the capture, as long as the minimum frame duration * of the physical and logical streams are the same.

    * + * @see CameraCharacteristics#LENS_DISTORTION * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION * @see CameraCharacteristics#LENS_POSE_REFERENCE * @see CameraCharacteristics#LENS_POSE_ROTATION * @see CameraCharacteristics#LENS_POSE_TRANSLATION - * @see CameraCharacteristics#LENS_RADIAL_DISTORTION * @see CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES */ @@ -1435,9 +1435,11 @@ public abstract class CameraMetadata { * for the external flash. Otherwise, this mode acts like ON.

    *

    When the external flash is turned off, AE mode should be changed to one of the * other available AE modes.

    - *

    If the camera device supports AE external flash mode, aeState must be - * FLASH_REQUIRED after the camera device finishes AE scan and it's too dark without + *

    If the camera device supports AE external flash mode, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} must + * be FLASH_REQUIRED after the camera device finishes AE scan and it's too dark without * flash.

    + * + * @see CaptureResult#CONTROL_AE_STATE * @see CaptureRequest#CONTROL_AE_MODE */ public static final int CONTROL_AE_MODE_ON_EXTERNAL_FLASH = 5; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 98901a1e69190bf801efb90af139b2b2cf989627..b0cbec71dfe6aaa01b9d179162d2ca6e1d9e9fc6 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -808,7 +808,7 @@ public final class CaptureRequest extends CameraMetadata> * *

    This method can be called for logical camera devices, which are devices that have * REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability and calls to - * {@link CameraCharacteristics#getPhysicalCameraIds} return a non-empty list of + * {@link CameraCharacteristics#getPhysicalCameraIds} return a non-empty set of * physical devices that are backing the logical camera. The camera Id included in the * 'physicalCameraId' argument selects an individual physical device that will receive * the customized capture request field.

    @@ -2791,8 +2791,10 @@ public final class CaptureRequest extends CameraMetadata> *
  • {@link #STATISTICS_OIS_DATA_MODE_ON ON}
  • *

    *

    Available values for this device:
    - * android.Statistics.info.availableOisDataModes

    + * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES android.statistics.info.availableOisDataModes}

    *

    Optional - This value may be {@code null} on some devices.

    + * + * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES * @see #STATISTICS_OIS_DATA_MODE_OFF * @see #STATISTICS_OIS_DATA_MODE_ON */ diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index e14dfa88fb8bf85df052136924bca7d0a4eb6804..633194243512f93c0b8c645835b175641e90bdff 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -1001,8 +1001,8 @@ public class CaptureResult extends CameraMetadata> { * * *

    If the camera device supports AE external flash mode (ON_EXTERNAL_FLASH is included in - * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_MODES android.control.aeAvailableModes}), aeState must be FLASH_REQUIRED after the camera device - * finishes AE scan and it's too dark without flash.

    + * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_MODES android.control.aeAvailableModes}), {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} must be FLASH_REQUIRED after + * the camera device finishes AE scan and it's too dark without flash.

    *

    For the above table, the camera device may skip reporting any state changes that happen * without application intervention (i.e. mode switch, trigger, locking). Any state that * can be skipped in that manner is called a transient state.

    @@ -1081,6 +1081,7 @@ public class CaptureResult extends CameraMetadata> { * @see CaptureRequest#CONTROL_AE_LOCK * @see CaptureRequest#CONTROL_AE_MODE * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER + * @see CaptureResult#CONTROL_AE_STATE * @see CaptureRequest#CONTROL_MODE * @see CaptureRequest#CONTROL_SCENE_MODE * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL @@ -2782,7 +2783,7 @@ public class CaptureResult extends CameraMetadata> { * from the main sensor along the +X axis (to the right from the user's perspective) will * report (0.03, 0, 0).

    *

    To transform a pixel coordinates between two cameras facing the same direction, first - * the source camera {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for. Then the source + * the source camera {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} must be corrected for. Then the source * camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs to be applied, followed by the * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the source camera, the translation of the source camera * relative to the destination camera, the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination @@ -2796,10 +2797,10 @@ public class CaptureResult extends CameraMetadata> { *

    Units: Meters

    *

    Optional - This value may be {@code null} on some devices.

    * + * @see CameraCharacteristics#LENS_DISTORTION * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION * @see CameraCharacteristics#LENS_POSE_REFERENCE * @see CameraCharacteristics#LENS_POSE_ROTATION - * @see CameraCharacteristics#LENS_RADIAL_DISTORTION */ @PublicKey public static final Key LENS_POSE_TRANSLATION = @@ -2845,7 +2846,7 @@ public class CaptureResult extends CameraMetadata> { * where (0,0) is the top-left of the * preCorrectionActiveArraySize rectangle. Once the pose and * intrinsic calibration transforms have been applied to a - * world point, then the {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} + * world point, then the {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} * transform needs to be applied, and the result adjusted to * be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate * system (where (0, 0) is the top-left of the @@ -2858,9 +2859,9 @@ public class CaptureResult extends CameraMetadata> { * coordinate system.

    *

    Optional - This value may be {@code null} on some devices.

    * + * @see CameraCharacteristics#LENS_DISTORTION * @see CameraCharacteristics#LENS_POSE_ROTATION * @see CameraCharacteristics#LENS_POSE_TRANSLATION - * @see CameraCharacteristics#LENS_RADIAL_DISTORTION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @@ -2902,11 +2903,58 @@ public class CaptureResult extends CameraMetadata> { *

    Optional - This value may be {@code null} on some devices.

    * * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION + * @deprecated + *

    This field was inconsistently defined in terms of its + * normalization. Use {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} instead.

    + * + * @see CameraCharacteristics#LENS_DISTORTION + */ + @Deprecated @PublicKey public static final Key LENS_RADIAL_DISTORTION = new Key("android.lens.radialDistortion", float[].class); + /** + *

    The correction coefficients to correct for this camera device's + * radial and tangential lens distortion.

    + *

    Replaces the deprecated {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} field, which was + * inconsistently defined.

    + *

    Three radial distortion coefficients [kappa_1, kappa_2, + * kappa_3] and two tangential distortion coefficients + * [kappa_4, kappa_5] that can be used to correct the + * lens's geometric distortion with the mapping equations:

    + *
     x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) +
    +     *        kappa_4 * (2 * x_i * y_i) + kappa_5 * ( r^2 + 2 * x_i^2 )
    +     *  y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) +
    +     *        kappa_5 * (2 * x_i * y_i) + kappa_4 * ( r^2 + 2 * y_i^2 )
    +     * 
    + *

    Here, [x_c, y_c] are the coordinates to sample in the + * input image that correspond to the pixel values in the + * corrected image at the coordinate [x_i, y_i]:

    + *
     correctedImage(x_i, y_i) = sample_at(x_c, y_c, inputImage)
    +     * 
    + *

    The pixel coordinates are defined in a coordinate system + * related to the {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} + * calibration fields; see that entry for details of the mapping stages. + * Both [x_i, y_i] and [x_c, y_c] + * have (0,0) at the lens optical center [c_x, c_y], and + * the range of the coordinates depends on the focal length + * terms of the intrinsic calibration.

    + *

    Finally, r represents the radial distance from the + * optical center, r^2 = x_i^2 + y_i^2.

    + *

    The distortion model used is the Brown-Conrady model.

    + *

    Units: + * Unitless coefficients.

    + *

    Optional - This value may be {@code null} on some devices.

    + * + * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION + * @see CameraCharacteristics#LENS_RADIAL_DISTORTION + */ + @PublicKey + public static final Key LENS_DISTORTION = + new Key("android.lens.distortion", float[].class); + /** *

    Mode of operation for the noise reduction algorithm.

    *

    The noise reduction algorithm attempts to improve image quality by removing @@ -2980,6 +3028,8 @@ public class CaptureResult extends CameraMetadata> { * Optional. Default value is FINAL.

    *

    Optional - This value may be {@code null} on some devices.

    * @deprecated + *

    Not used in HALv3 or newer

    + * @hide */ @Deprecated @@ -2996,6 +3046,8 @@ public class CaptureResult extends CameraMetadata> { * > 0

    *

    Optional - This value may be {@code null} on some devices.

    * @deprecated + *

    Not used in HALv3 or newer

    + * @hide */ @Deprecated @@ -3776,6 +3828,8 @@ public class CaptureResult extends CameraMetadata> { * * @see CaptureRequest#COLOR_CORRECTION_GAINS * @deprecated + *

    Never fully implemented or specified; do not use

    + * @hide */ @Deprecated @@ -3800,6 +3854,8 @@ public class CaptureResult extends CameraMetadata> { * regardless of the android.control.* current values.

    *

    Optional - This value may be {@code null} on some devices.

    * @deprecated + *

    Never fully implemented or specified; do not use

    + * @hide */ @Deprecated @@ -3918,8 +3974,10 @@ public class CaptureResult extends CameraMetadata> { *
  • {@link #STATISTICS_OIS_DATA_MODE_ON ON}
  • *

    *

    Available values for this device:
    - * android.Statistics.info.availableOisDataModes

    + * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES android.statistics.info.availableOisDataModes}

    *

    Optional - This value may be {@code null} on some devices.

    + * + * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES * @see #STATISTICS_OIS_DATA_MODE_OFF * @see #STATISTICS_OIS_DATA_MODE_ON */ diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java index 0be45a0c9779f0eadc87e791aca6f3de0ed82a16..4e20cb8d129ea4a5e280523b41e7b996c50f88ff 100644 --- a/core/java/android/hardware/camera2/TotalCaptureResult.java +++ b/core/java/android/hardware/camera2/TotalCaptureResult.java @@ -138,7 +138,7 @@ public final class TotalCaptureResult extends CaptureResult { * *

    This function can be called for logical multi-camera devices, which are devices that have * REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability and calls to {@link - * CameraCharacteristics#getPhysicalCameraIds} return a non-empty list of physical devices that + * CameraCharacteristics#getPhysicalCameraIds} return a non-empty set of physical devices that * are backing the logical camera.

    * *

    If one or more streams from the underlying physical cameras were requested by the diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index e81fbeed34b033a7259e15470b7a85b7d0a3a5cd..a3b2d22deccbf8b0034d7facc5b6322c70136e7c 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -667,6 +667,45 @@ public final class DisplayManager { mGlobal.setBrightnessConfigurationForUser(c, userId, packageName); } + /** + * Gets the global display brightness configuration or the default curve if one hasn't been set. + * + * @hide + */ + @SystemApi + @TestApi + @RequiresPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) + public BrightnessConfiguration getBrightnessConfiguration() { + return getBrightnessConfigurationForUser(mContext.getUserId()); + } + + /** + * Gets the global display brightness configuration or the default curve if one hasn't been set + * for a specific user. + * + * Note this requires the INTERACT_ACROSS_USERS permission if getting the configuration for a + * user other than the one you're currently running as. + * + * @hide + */ + public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) { + return mGlobal.getBrightnessConfigurationForUser(userId); + } + + /** + * Gets the default global display brightness configuration or null one hasn't + * been configured. + * + * @hide + */ + @SystemApi + @TestApi + @RequiresPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) + @Nullable + public BrightnessConfiguration getDefaultBrightnessConfiguration() { + return mGlobal.getDefaultBrightnessConfiguration(); + } + /** * Temporarily sets the brightness of the display. *

    diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index d7f7c865b8fb941b77d384062544b3c372336cc0..1f67a6bf71a721b7ecf967aa92baf50598d223bb 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -489,6 +489,32 @@ public final class DisplayManagerGlobal { } } + /** + * Gets the global brightness configuration for a given user or null if one hasn't been set. + * + * @hide + */ + public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) { + try { + return mDm.getBrightnessConfigurationForUser(userId); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * Gets the default brightness configuration or null if one hasn't been configured. + * + * @hide + */ + public BrightnessConfiguration getDefaultBrightnessConfiguration() { + try { + return mDm.getDefaultBrightnessConfiguration(); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + /** * Temporarily sets the brightness of the display. *

    diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index f468942cc95138ea7a1a780d74ec9533c1f908bc..504f840af5bf605b2c4b77fda8c78e73a1dee184 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/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index 0571ae1fe82564b44fe4e7a6e3b89328bb1916b6..9fcb9d3fc265aa5afde4734129e9dc276cd5df60 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -96,6 +96,14 @@ interface IDisplayManager { void setBrightnessConfigurationForUser(in BrightnessConfiguration c, int userId, String packageName); + // Gets the global brightness configuration for a given user. Requires + // CONFIGURE_DISPLAY_BRIGHTNESS, and INTERACT_ACROSS_USER if the user is not + // the same as the calling user. + BrightnessConfiguration getBrightnessConfigurationForUser(int userId); + + // Gets the default brightness configuration if configured. + BrightnessConfiguration getDefaultBrightnessConfiguration(); + // Temporarily sets the display brightness. void setTemporaryBrightness(int brightness); diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 9e0c680cafa1ffe038d5dfed053f62e385aa5be1..97868fa268ad81fc51a372c3a1026d0bc567cdb0 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -26,8 +26,6 @@ import android.os.IBinder; import android.view.InputDevice; import android.view.InputEvent; import android.view.PointerIcon; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; /** @hide */ interface IInputManager { @@ -67,11 +65,6 @@ interface IInputManager { String keyboardLayoutDescriptor); void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, String keyboardLayoutDescriptor); - KeyboardLayout getKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, - in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype); - void setKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, - in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype, - String keyboardLayoutDescriptor); // Registers an input devices changed listener. void registerInputDevicesChangedListener(IInputDevicesChangedListener listener); diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index fdea5a2f93518d63efa44ff7fc1da7a0b48ae7fc..6ae7a146a7b72dbfe133d160bb47120b9d0dea26 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -17,7 +17,6 @@ package android.hardware.input; import android.annotation.IntDef; -import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; @@ -43,8 +42,6 @@ import android.view.InputDevice; import android.view.InputEvent; import android.view.MotionEvent; import android.view.PointerIcon; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; import com.android.internal.os.SomeArgs; @@ -703,52 +700,6 @@ public final class InputManager { } } - - /** - * Gets the keyboard layout for the specified input device and IME subtype. - * - * @param identifier The identifier for the input device. - * @param inputMethodInfo The input method. - * @param inputMethodSubtype The input method subtype. {@code null} if this input method does - * not support any subtype. - * - * @return The associated {@link KeyboardLayout}, or null if one has not been set. - * - * @hide - */ - @Nullable - public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, - InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype) { - try { - return mIm.getKeyboardLayoutForInputDevice( - identifier, inputMethodInfo, inputMethodSubtype); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } - } - - /** - * Sets the keyboard layout for the specified input device and IME subtype pair. - * - * @param identifier The identifier for the input device. - * @param inputMethodInfo The input method with which to associate the keyboard layout. - * @param inputMethodSubtype The input method subtype which which to associate the keyboard - * layout. {@code null} if this input method does not support any subtype. - * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to set - * - * @hide - */ - public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, - InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype, - String keyboardLayoutDescriptor) { - try { - mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo, - inputMethodSubtype, keyboardLayoutDescriptor); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } - } - /** * Gets the TouchCalibration applied to the specified input device's coordinates. * diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java index 4ea0f55218a94d287253576fbdc206e3054c2852..eb7ea67eb8862fcbc1a601d7b63bc0bf5f7a7068 100644 --- a/core/java/android/hardware/input/InputManagerInternal.java +++ b/core/java/android/hardware/input/InputManagerInternal.java @@ -16,11 +16,8 @@ package android.hardware.input; -import android.annotation.Nullable; import android.hardware.display.DisplayViewport; import android.view.InputEvent; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; import java.util.List; @@ -45,16 +42,6 @@ public abstract class InputManagerInternal { */ public abstract void setInteractive(boolean interactive); - /** - * Notifies that InputMethodManagerService switched the current input method subtype. - * - * @param userId user id that indicates who is using the specified input method and subtype. - * @param inputMethodInfo {@code null} when no input method is selected. - * @param subtype {@code null} when {@code inputMethodInfo} does has no subtype. - */ - public abstract void onInputMethodSubtypeChanged(int userId, - @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype); - /** * Toggles Caps Lock state for input device with specific id. * diff --git a/core/java/android/hardware/input/TouchCalibration.java b/core/java/android/hardware/input/TouchCalibration.java index 15503ed0b9009e1786deaacc429e8e88adc55a3f..025fad046eb8df26d80666ee05cbd4dcb9fe62ac 100644 --- a/core/java/android/hardware/input/TouchCalibration.java +++ b/core/java/android/hardware/input/TouchCalibration.java @@ -123,10 +123,4 @@ public class TouchCalibration implements Parcelable { Float.floatToIntBits(mYScale) ^ Float.floatToIntBits(mYOffset); } - - @Override - public String toString() { - return String.format("[%f, %f, %f, %f, %f, %f]", - mXScale, mXYMix, mXOffset, mYXMix, mYScale, mYOffset); - } } diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index b635088cb11bb69eb9de1c26096c6c9fee04c342..dde8a33271723a19b387725443b58d284004f460 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -16,6 +16,14 @@ package android.hardware.soundtrigger; +import static android.system.OsConstants.EINVAL; +import static android.system.OsConstants.ENODEV; +import static android.system.OsConstants.ENOSYS; +import static android.system.OsConstants.EPERM; +import static android.system.OsConstants.EPIPE; + +import android.annotation.Nullable; +import android.annotation.SystemApi; import android.media.AudioFormat; import android.os.Handler; import android.os.Parcel; @@ -25,22 +33,33 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.UUID; -import static android.system.OsConstants.*; - /** * The SoundTrigger class provides access via JNI to the native service managing * the sound trigger HAL. * * @hide */ +@SystemApi public class SoundTrigger { + private SoundTrigger() { + } + + /** + * Status code used when the operation succeeded + */ public static final int STATUS_OK = 0; + /** @hide */ public static final int STATUS_ERROR = Integer.MIN_VALUE; + /** @hide */ public static final int STATUS_PERMISSION_DENIED = -EPERM; + /** @hide */ public static final int STATUS_NO_INIT = -ENODEV; + /** @hide */ public static final int STATUS_BAD_VALUE = -EINVAL; + /** @hide */ public static final int STATUS_DEAD_OBJECT = -EPIPE; + /** @hide */ public static final int STATUS_INVALID_OPERATION = -ENOSYS; /***************************************************************************** @@ -48,6 +67,8 @@ public class SoundTrigger { * managed by the native sound trigger service. Each module has a unique * ID used to target any API call to this paricular module. Module * properties are returned by listModules() method. + * + * @hide ****************************************************************************/ public static class ModuleProperties implements Parcelable { /** Unique module ID provided by the native service */ @@ -187,6 +208,8 @@ public class SoundTrigger { * implementation to detect a particular sound pattern. * A specialized version {@link KeyphraseSoundModel} is defined for key phrase * sound models. + * + * @hide ****************************************************************************/ public static class SoundModel { /** Undefined sound model type */ @@ -261,6 +284,8 @@ public class SoundTrigger { /***************************************************************************** * A Keyphrase describes a key phrase that can be detected by a * {@link KeyphraseSoundModel} + * + * @hide ****************************************************************************/ public static class Keyphrase implements Parcelable { /** Unique identifier for this keyphrase */ @@ -382,6 +407,8 @@ public class SoundTrigger { * A KeyphraseSoundModel is a specialized {@link SoundModel} for key phrases. * It contains data needed by the hardware to detect a certain number of key phrases * and the list of corresponding {@link Keyphrase} descriptors. + * + * @hide ****************************************************************************/ public static class KeyphraseSoundModel extends SoundModel implements Parcelable { /** Key phrases in this sound model */ @@ -468,6 +495,8 @@ public class SoundTrigger { /***************************************************************************** * A GenericSoundModel is a specialized {@link SoundModel} for non-voice sound * patterns. + * + * @hide ****************************************************************************/ public static class GenericSoundModel extends SoundModel implements Parcelable { @@ -524,52 +553,115 @@ public class SoundTrigger { /** * Modes for key phrase recognition */ - /** Simple recognition of the key phrase */ + + /** + * Simple recognition of the key phrase + * + * @hide + */ public static final int RECOGNITION_MODE_VOICE_TRIGGER = 0x1; - /** Trigger only if one user is identified */ + /** + * Trigger only if one user is identified + * + * @hide + */ public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 0x2; - /** Trigger only if one user is authenticated */ + /** + * Trigger only if one user is authenticated + * + * @hide + */ public static final int RECOGNITION_MODE_USER_AUTHENTICATION = 0x4; /** * Status codes for {@link RecognitionEvent} */ - /** Recognition success */ + /** + * Recognition success + * + * @hide + */ public static final int RECOGNITION_STATUS_SUCCESS = 0; - /** Recognition aborted (e.g. capture preempted by anotehr use case */ + /** + * Recognition aborted (e.g. capture preempted by anotehr use case + * + * @hide + */ public static final int RECOGNITION_STATUS_ABORT = 1; - /** Recognition failure */ + /** + * Recognition failure + * + * @hide + */ public static final int RECOGNITION_STATUS_FAILURE = 2; /** * A RecognitionEvent is provided by the - * {@link StatusListener#onRecognition(RecognitionEvent)} + * {@code StatusListener#onRecognition(RecognitionEvent)} * callback upon recognition success or failure. */ - public static class RecognitionEvent implements Parcelable { - /** Recognition status e.g {@link #RECOGNITION_STATUS_SUCCESS} */ + public static class RecognitionEvent { + /** + * Recognition status e.g RECOGNITION_STATUS_SUCCESS + * + * @hide + */ public final int status; - /** Sound Model corresponding to this event callback */ + /** + * + * Sound Model corresponding to this event callback + * + * @hide + */ public final int soundModelHandle; - /** True if it is possible to capture audio from this utterance buffered by the hardware */ + /** + * True if it is possible to capture audio from this utterance buffered by the hardware + * + * @hide + */ public final boolean captureAvailable; - /** Audio session ID to be used when capturing the utterance with an AudioRecord - * if captureAvailable() is true. */ + /** + * Audio session ID to be used when capturing the utterance with an AudioRecord + * if captureAvailable() is true. + * + * @hide + */ public final int captureSession; - /** Delay in ms between end of model detection and start of audio available for capture. - * A negative value is possible (e.g. if keyphrase is also available for capture) */ + /** + * Delay in ms between end of model detection and start of audio available for capture. + * A negative value is possible (e.g. if keyphrase is also available for capture) + * + * @hide + */ public final int captureDelayMs; - /** Duration in ms of audio captured before the start of the trigger. 0 if none. */ + /** + * Duration in ms of audio captured before the start of the trigger. 0 if none. + * + * @hide + */ public final int capturePreambleMs; - /** True if the trigger (key phrase capture is present in binary data */ + /** + * True if the trigger (key phrase capture is present in binary data + * + * @hide + */ public final boolean triggerInData; - /** Audio format of either the trigger in event data or to use for capture of the - * rest of the utterance */ - public AudioFormat captureFormat; - /** Opaque data for use by system applications who know about voice engine internals, - * typically during enrollment. */ + /** + * Audio format of either the trigger in event data or to use for capture of the + * rest of the utterance + * + * @hide + */ + public final AudioFormat captureFormat; + /** + * Opaque data for use by system applications who know about voice engine internals, + * typically during enrollment. + * + * @hide + */ public final byte[] data; + /** @hide */ public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, boolean triggerInData, AudioFormat captureFormat, byte[] data) { @@ -584,6 +676,46 @@ public class SoundTrigger { this.data = data; } + /** + * Check if is possible to capture audio from this utterance buffered by the hardware. + * + * @return {@code true} iff a capturing is possible + */ + public boolean isCaptureAvailable() { + return captureAvailable; + } + + /** + * Get the audio format of either the trigger in event data or to use for capture of the + * rest of the utterance + * + * @return the audio format + */ + @Nullable public AudioFormat getCaptureFormat() { + return captureFormat; + } + + /** + * Get Audio session ID to be used when capturing the utterance with an {@link AudioRecord} + * if {@link #isCaptureAvailable()} is true. + * + * @return The id of the capture session + */ + public int getCaptureSession() { + return captureSession; + } + + /** + * Get the opaque data for use by system applications who know about voice engine + * internals, typically during enrollment. + * + * @return The data of the event + */ + public byte[] getData() { + return data; + } + + /** @hide */ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public RecognitionEvent createFromParcel(Parcel in) { @@ -595,6 +727,7 @@ public class SoundTrigger { } }; + /** @hide */ protected static RecognitionEvent fromParcel(Parcel in) { int status = in.readInt(); int soundModelHandle = in.readInt(); @@ -619,12 +752,12 @@ public class SoundTrigger { captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data); } - @Override + /** @hide */ public int describeContents() { return 0; } - @Override + /** @hide */ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(status); dest.writeInt(soundModelHandle); @@ -726,6 +859,8 @@ public class SoundTrigger { * A RecognitionConfig is provided to * {@link SoundTriggerModule#startRecognition(int, RecognitionConfig)} to configure the * recognition request. + * + * @hide */ public static class RecognitionConfig implements Parcelable { /** True if the DSP should capture the trigger sound and make it available for further @@ -744,7 +879,7 @@ public class SoundTrigger { public final byte[] data; public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers, - KeyphraseRecognitionExtra keyphrases[], byte[] data) { + KeyphraseRecognitionExtra[] keyphrases, byte[] data) { this.captureRequested = captureRequested; this.allowMultipleTriggers = allowMultipleTriggers; this.keyphrases = keyphrases; @@ -799,6 +934,8 @@ public class SoundTrigger { * When used in a {@link RecognitionConfig} it indicates the minimum confidence level that * should trigger a recognition. * - The user ID is derived from the system ID {@link android.os.UserHandle#getIdentifier()}. + * + * @hide */ public static class ConfidenceLevel implements Parcelable { public final int userId; @@ -872,6 +1009,8 @@ public class SoundTrigger { /** * Additional data conveyed by a {@link KeyphraseRecognitionEvent} * for a key phrase detection. + * + * @hide */ public static class KeyphraseRecognitionExtra implements Parcelable { /** The keyphrase ID */ @@ -970,8 +1109,10 @@ public class SoundTrigger { /** * Specialized {@link RecognitionEvent} for a key phrase detection. + * + * @hide */ - public static class KeyphraseRecognitionEvent extends RecognitionEvent { + public static class KeyphraseRecognitionEvent extends RecognitionEvent implements Parcelable { /** Indicates if the key phrase is present in the buffered audio available for capture */ public final KeyphraseRecognitionExtra[] keyphraseExtras; @@ -1091,8 +1232,10 @@ public class SoundTrigger { /** * Sub-class of RecognitionEvent specifically for sound-trigger based sound * models(non-keyphrase). Currently does not contain any additional fields. + * + * @hide */ - public static class GenericRecognitionEvent extends RecognitionEvent { + public static class GenericRecognitionEvent extends RecognitionEvent implements Parcelable { public GenericRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, boolean triggerInData, AudioFormat captureFormat, @@ -1140,13 +1283,19 @@ public class SoundTrigger { /** * Status codes for {@link SoundModelEvent} */ - /** Sound Model was updated */ + /** + * Sound Model was updated + * + * @hide + */ public static final int SOUNDMODEL_STATUS_UPDATED = 0; /** * A SoundModelEvent is provided by the * {@link StatusListener#onSoundModelUpdate(SoundModelEvent)} * callback when a sound model has been updated by the implementation + * + * @hide */ public static class SoundModelEvent implements Parcelable { /** Status e.g {@link #SOUNDMODEL_STATUS_UPDATED} */ @@ -1231,9 +1380,17 @@ public class SoundTrigger { * Native service state. {@link StatusListener#onServiceStateChange(int)} */ // Keep in sync with system/core/include/system/sound_trigger.h - /** Sound trigger service is enabled */ + /** + * Sound trigger service is enabled + * + * @hide + */ public static final int SERVICE_STATE_ENABLED = 0; - /** Sound trigger service is disabled */ + /** + * Sound trigger service is disabled + * + * @hide + */ public static final int SERVICE_STATE_DISABLED = 1; /** @@ -1245,6 +1402,8 @@ public class SoundTrigger { * - {@link #STATUS_NO_INIT} if the native service cannot be reached * - {@link #STATUS_BAD_VALUE} if modules is null * - {@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails + * + * @hide */ public static native int listModules(ArrayList modules); @@ -1256,6 +1415,8 @@ public class SoundTrigger { * @param handler the Handler that will receive the callabcks. Can be null if default handler * is OK. * @return a valid sound module in case of success or null in case of error. + * + * @hide */ public static SoundTriggerModule attachModule(int moduleId, StatusListener listener, @@ -1270,6 +1431,8 @@ public class SoundTrigger { /** * Interface provided by the client application when attaching to a {@link SoundTriggerModule} * to received recognition and error notifications. + * + * @hide */ public static interface StatusListener { /** diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index b3bf092aeffebc7534e752473af7aa8c5e658758..b4c8a5e504bc80204a873ba92bc5f403e5caa7a9 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. + * + *

    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.

    + * + *

    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.

    + * + *

    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.

    + * + * @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. + * + *

    To avoid compatibility issues, IME developers should not use this flag.

    + * + * @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. + * + *

    To avoid compatibility issues, IME developers should not use this flag.

    + * + * @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. + * + *

    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}.

    + * + *

    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.

    + * + * @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. + * + *

    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.

    + * + * @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. - * - *

    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. + * + *

    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.

    + * + *

    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)}.

    + * + * @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 2bb43bd36be3bd6caddcc731ccbe8f02a5553e30..e84f91314386aea00316f318840920c7354c43e9 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 1fd9423b6128ba38e5978d829e878dea8eb9c9a7..1e75bf461a705267a585875d949797e738f83c2c 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. @@ -38,6 +39,18 @@ oneway interface INetdEventCallback { void onDnsEvent(String hostname, in String[] ipAddresses, int ipAddressesCount, long timestamp, 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/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index b60984771a2dc2c29391f37900c8c018d380f1bd..fbf305633a71062f221793850061c51108055e8a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -58,14 +58,18 @@ public final class IpSecManager { private static final String TAG = "IpSecManager"; /** - * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute - * applies to traffic towards the host. + * Used when applying a transform to direct traffic through an {@link IpSecTransform} + * towards the host. + * + *

    See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. */ public static final int DIRECTION_IN = 0; /** - * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute - * applies to traffic from the host. + * Used when applying a transform to direct traffic through an {@link IpSecTransform} + * away from the host. + * + *

    See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. */ public static final int DIRECTION_OUT = 1; @@ -301,19 +305,21 @@ public final class IpSecManager { * *

    Rekey Procedure

    * - *

    When applying a new tranform to a socket, the previous transform will be removed. However, - * inbound traffic on the old transform will continue to be decrypted until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures - * where both transforms are valid until both endpoints are using the new transform and all - * in-flight packets have been received. + *

    When applying a new tranform to a socket in the outbound direction, the previous transform + * will be removed and the new transform will take effect immediately, sending all traffic on + * the new transform; however, when applying a transform in the inbound direction, traffic + * on the old transform will continue to be decrypted and delivered until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey + * procedures where both transforms are valid until both endpoints are using the new transform + * and all in-flight packets have been received. * * @param socket a stream socket - * @param direction the policy direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} + * @param direction the direction in which the transform should be applied * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ public void applyTransportModeTransform( - Socket socket, int direction, IpSecTransform transform) + Socket socket, @PolicyDirection int direction, IpSecTransform transform) throws IOException { applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -334,19 +340,22 @@ public final class IpSecManager { * *

    Rekey Procedure

    * - *

    When applying a new tranform to a socket, the previous transform will be removed. However, - * inbound traffic on the old transform will continue to be decrypted until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures - * where both transforms are valid until both endpoints are using the new transform and all - * in-flight packets have been received. + *

    When applying a new tranform to a socket in the outbound direction, the previous transform + * will be removed and the new transform will take effect immediately, sending all traffic on + * the new transform; however, when applying a transform in the inbound direction, traffic + * on the old transform will continue to be decrypted and delivered until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey + * procedures where both transforms are valid until both endpoints are using the new transform + * and all in-flight packets have been received. * * @param socket a datagram socket - * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT + * @param direction the direction in which the transform should be applied * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ public void applyTransportModeTransform( - DatagramSocket socket, int direction, IpSecTransform transform) throws IOException { + DatagramSocket socket, @PolicyDirection int direction, IpSecTransform transform) + throws IOException { applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -366,19 +375,21 @@ public final class IpSecManager { * *

    Rekey Procedure

    * - *

    When applying a new tranform to a socket, the previous transform will be removed. However, - * inbound traffic on the old transform will continue to be decrypted until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures - * where both transforms are valid until both endpoints are using the new transform and all - * in-flight packets have been received. + *

    When applying a new tranform to a socket in the outbound direction, the previous transform + * will be removed and the new transform will take effect immediately, sending all traffic on + * the new transform; however, when applying a transform in the inbound direction, traffic + * on the old transform will continue to be decrypted and delivered until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey + * procedures where both transforms are valid until both endpoints are using the new transform + * and all in-flight packets have been received. * * @param socket a socket file descriptor - * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT + * @param direction the direction in which the transform should be applied * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ public void applyTransportModeTransform( - FileDescriptor socket, int direction, IpSecTransform transform) + FileDescriptor socket, @PolicyDirection int direction, IpSecTransform transform) throws IOException { // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() // constructor takes control and closes the user's FD when we exit the method. @@ -389,21 +400,6 @@ public final class IpSecManager { } } - /** - * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to - * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to - * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic). - * Applications should probably not use this API directly. Instead, they should use {@link - * VpnService} to provide VPN capability in a more generic fashion. - * - *

    TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. - * - * @param net a {@link Network} that will be tunneled via IP Sec. - * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform. - * @hide - */ - public void applyTunnelModeTransform(Network net, IpSecTransform transform) {} - /** * Remove an IPsec transform from a stream socket. * @@ -770,7 +766,12 @@ public final class IpSecManager { } /** - * Apply a transform to the IpSecTunnelInterface + * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will + * tunnel all traffic for the given direction through the underlying network's interface with + * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional + * IP header and IPsec Header on all inbound traffic). + *

    Applications should probably not use this API directly. + * * * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied * transform. @@ -783,8 +784,8 @@ public final class IpSecManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_STACK) - public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction, - IpSecTransform transform) throws IOException { + public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, + @PolicyDirection int direction, IpSecTransform transform) throws IOException { try { mService.applyTunnelModeTransform( tunnel.getResourceId(), direction, transform.getResourceId()); @@ -792,6 +793,7 @@ public final class IpSecManager { throw e.rethrowFromSystemServer(); } } + /** * Construct an instance of IpSecManager within an application context. * diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index b02d48dc438f649aec7ec9e6105f30f383ef279e..c3f23a1cca9ff9ceab3babc8582130f0b76aeee7 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -225,7 +225,7 @@ public final class NfcAdapter { * Indicates the Secure Element on which the transaction occurred. * eSE1...eSEn for Embedded Secure Elements, SIM1...SIMn for UICC, etc. */ - public static final String EXTRA_SE_NAME = "android.nfc.extra.SE_NAME"; + public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME"; public static final int STATE_OFF = 1; public static final int STATE_TURNING_ON = 2; diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 7bc5d5bd33bfd94289684f97a4fcc370d6155004..b16e7d7add0daac7798e5de72f9e38fef2ab05b7 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -23,6 +23,7 @@ import android.content.pm.ApplicationInfo; import android.server.ServerProtoEnums; import android.service.batterystats.BatteryStatsServiceDumpProto; import android.telephony.SignalStrength; +import android.telephony.TelephonyManager; import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.LongSparseArray; @@ -2270,27 +2271,8 @@ public abstract class BatteryStats implements Parcelable { */ public abstract int getMobileRadioActiveUnknownCount(int which); - public static final int DATA_CONNECTION_NONE = SystemProto.DataConnection.NONE; // 0 - public static final int DATA_CONNECTION_GPRS = SystemProto.DataConnection.GPRS; // 1 - public static final int DATA_CONNECTION_EDGE = SystemProto.DataConnection.EDGE; // 2 - public static final int DATA_CONNECTION_UMTS = SystemProto.DataConnection.UMTS; // 3 - public static final int DATA_CONNECTION_CDMA = SystemProto.DataConnection.CDMA; // 4 - public static final int DATA_CONNECTION_EVDO_0 = SystemProto.DataConnection.EVDO_0; // 5 - public static final int DATA_CONNECTION_EVDO_A = SystemProto.DataConnection.EVDO_A; // 6 - public static final int DATA_CONNECTION_1xRTT = SystemProto.DataConnection.ONE_X_RTT; // 7 - public static final int DATA_CONNECTION_HSDPA = SystemProto.DataConnection.HSDPA; // 8 - public static final int DATA_CONNECTION_HSUPA = SystemProto.DataConnection.HSUPA; // 9 - public static final int DATA_CONNECTION_HSPA = SystemProto.DataConnection.HSPA; // 10 - public static final int DATA_CONNECTION_IDEN = SystemProto.DataConnection.IDEN; // 11 - public static final int DATA_CONNECTION_EVDO_B = SystemProto.DataConnection.EVDO_B; // 12 - public static final int DATA_CONNECTION_LTE = SystemProto.DataConnection.LTE; // 13 - public static final int DATA_CONNECTION_EHRPD = SystemProto.DataConnection.EHRPD; // 14 - public static final int DATA_CONNECTION_HSPAP = SystemProto.DataConnection.HSPAP; // 15 - public static final int DATA_CONNECTION_GSM = SystemProto.DataConnection.GSM; // 16 - public static final int DATA_CONNECTION_TD_SCDMA = SystemProto.DataConnection.TD_SCDMA; // 17 - public static final int DATA_CONNECTION_IWLAN = SystemProto.DataConnection.IWLAN; // 18 - public static final int DATA_CONNECTION_LTE_CA = SystemProto.DataConnection.LTE_CA; // 19 - public static final int DATA_CONNECTION_OTHER = SystemProto.DataConnection.OTHER; // 20 + public static final int DATA_CONNECTION_NONE = 0; + public static final int DATA_CONNECTION_OTHER = TelephonyManager.MAX_NETWORK_TYPE + 1; static final String[] DATA_CONNECTION_NAMES = { "none", "gprs", "edge", "umts", "cdma", "evdo_0", "evdo_A", @@ -7613,8 +7595,18 @@ public abstract class BatteryStats implements Parcelable { // Phone data connection (DATA_CONNECTION_TIME_DATA and DATA_CONNECTION_COUNT_DATA) for (int i = 0; i < NUM_DATA_CONNECTION_TYPES; ++i) { + // Map OTHER to TelephonyManager.NETWORK_TYPE_UNKNOWN and mark NONE as a boolean. + boolean isNone = (i == DATA_CONNECTION_NONE); + int telephonyNetworkType = i; + if (i == DATA_CONNECTION_OTHER) { + telephonyNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + } final long pdcToken = proto.start(SystemProto.DATA_CONNECTION); - proto.write(SystemProto.DataConnection.NAME, i); + if (isNone) { + proto.write(SystemProto.DataConnection.IS_NONE, isNone); + } else { + proto.write(SystemProto.DataConnection.NAME, telephonyNetworkType); + } dumpTimer(proto, SystemProto.DataConnection.TOTAL, getPhoneDataConnectionTimer(i), rawRealtimeUs, which); proto.end(pdcToken); diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index ff7c0c6681c680fe0e8f924a54458906411b640f..44bd35aa896f698f8c9ddd971953e39f47b66546 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -376,7 +376,9 @@ public class Binder implements IBinder { * Add the calling thread to the IPC thread pool. This function does * not return until the current process is exiting. */ - public static final native void joinThreadPool(); + public static final void joinThreadPool() { + BinderInternal.joinThreadPool(); + } /** * Returns true if the specified interface is a proxy. diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index 0417ded829e8cba7f3ba2bcf34bf478d471b0a92..f5bca04ae1044d7fc8318ac25f67808d28e5a330 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -220,7 +220,7 @@ public class Handler { * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to - * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. + * the synchronization barriers introduced by conditions such as display vsync. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. @@ -236,6 +236,43 @@ public class Handler { mAsynchronous = async; } + /** + * Create a new Handler whose posted messages and runnables are not subject to + * synchronization barriers such as display vsync. + * + *

    Messages sent to an async handler are guaranteed to be ordered with respect to one another, + * but not necessarily with respect to messages from other Handlers.

    + * + * @see #createAsync(Looper, Callback) to create an async Handler with custom message handling. + * + * @param looper the Looper that the new Handler should be bound to + * @return a new async Handler instance + */ + @NonNull + public static Handler createAsync(@NonNull Looper looper) { + if (looper == null) throw new NullPointerException("looper must not be null"); + return new Handler(looper, null, true); + } + + /** + * Create a new Handler whose posted messages and runnables are not subject to + * synchronization barriers such as display vsync. + * + *

    Messages sent to an async handler are guaranteed to be ordered with respect to one another, + * but not necessarily with respect to messages from other Handlers.

    + * + * @see #createAsync(Looper) to create an async Handler without custom message handling. + * + * @param looper the Looper that the new Handler should be bound to + * @return a new async Handler instance + */ + @NonNull + public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) { + if (looper == null) throw new NullPointerException("looper must not be null"); + if (callback == null) throw new NullPointerException("callback must not be null"); + return new Handler(looper, callback, true); + } + /** @hide */ @NonNull public static Handler getMain() { diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index 1681f11fa526374af847a10c560c1e718e816ae6..13e4e38df5f63a727cf5c628d3afc21a71da4c98 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -65,4 +65,7 @@ interface IPowerManager // sets the attention light (used by phone app only) void setAttentionLight(boolean on, int color); + + // controls whether PowerManager should doze after the screen turns off or not + void setDozeAfterScreenOff(boolean on); } diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl index 29c298e31ae98686f80888990cd7ed9e39a14309..402c995452e807765ebfca457cfe444199fc5198 100644 --- a/core/java/android/os/IStatsCompanionService.aidl +++ b/core/java/android/os/IStatsCompanionService.aidl @@ -74,6 +74,7 @@ interface IStatsCompanionService { */ oneway void sendSubscriberBroadcast(in IBinder intentSender, long configUid, long configId, long subscriptionId, long subscriptionRuleId, + in String[] cookies, in StatsDimensionsValue dimensionsValue); /** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */ diff --git a/core/java/android/os/IncidentManager.java b/core/java/android/os/IncidentManager.java index 9b6d6e56407ab2af53099c6282e7afe499add977..0e6652d471a54f337068376cd5e0f635b37dfb50 100644 --- a/core/java/android/os/IncidentManager.java +++ b/core/java/android/os/IncidentManager.java @@ -21,7 +21,6 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; -import android.provider.Settings; import android.util.Slog; /** @@ -57,47 +56,6 @@ public class IncidentManager { reportIncidentInternal(args); } - /** - * Convenience method to trigger an incident report and put it in dropbox. - *

    - * The fields that are reported will be looked up in the system setting named by - * the settingName parameter. The setting must match one of these patterns: - * The string "disabled": The report will not be taken. - * The string "all": The report will taken with all sections. - * The string "none": The report will taken with no sections, but with the header. - * A comma separated list of field numbers: The report will have these fields. - *

    - * The header parameter will be added as a header for the incident report. Fill in a - * {@link android.util.proto.ProtoOutputStream ProtoOutputStream}, and then call the - * {@link android.util.proto.ProtoOutputStream#bytes bytes()} method to retrieve - * the encoded data for the header. - */ - @RequiresPermission(allOf = { - android.Manifest.permission.DUMP, - android.Manifest.permission.PACKAGE_USAGE_STATS - }) - public void reportIncident(String settingName, byte[] headerProto) { - // Sections - String setting = Settings.Global.getString(mContext.getContentResolver(), settingName); - IncidentReportArgs args; - try { - args = IncidentReportArgs.parseSetting(setting); - } catch (IllegalArgumentException ex) { - Slog.w(TAG, "Bad value for incident report setting '" + settingName + "'", ex); - return; - } - if (args == null) { - Slog.i(TAG, String.format("Incident report requested but disabled with " - + "settings [name: %s, value: %s]", settingName, setting)); - return; - } - - args.addHeader(headerProto); - - Slog.i(TAG, "Taking incident report: " + settingName); - reportIncidentInternal(args); - } - private class IncidentdDeathRecipient implements IBinder.DeathRecipient { @Override public void binderDied() { diff --git a/core/java/android/os/IncidentReportArgs.java b/core/java/android/os/IncidentReportArgs.java index 9fa129cb98b491901d5236899f50f84fc80d1385..1aeac5f53be01cf33951bfb7d25149b3f62c47e7 100644 --- a/core/java/android/os/IncidentReportArgs.java +++ b/core/java/android/os/IncidentReportArgs.java @@ -188,53 +188,5 @@ public final class IncidentReportArgs implements Parcelable { public void addHeader(byte[] header) { mHeaders.add(header); } - - /** - * Parses an incident report config as described in the system setting. - * - * @see IncidentManager#reportIncident - */ - public static IncidentReportArgs parseSetting(String setting) - throws IllegalArgumentException { - if (setting == null || setting.length() == 0) { - return null; - } - setting = setting.trim(); - if (setting.length() == 0 || "disabled".equals(setting)) { - return null; - } - - final IncidentReportArgs args = new IncidentReportArgs(); - - if ("all".equals(setting)) { - args.setAll(true); - return args; - } else if ("none".equals(setting)) { - return args; - } - - final String[] splits = setting.split(","); - final int N = splits.length; - for (int i=0; i callbacks = new ArrayList(sChangeCallbacks); for (int i=0; i This results in {@link #shouldSystemBlockNumber} returning {@code false} independent @@ -342,13 +383,19 @@ public class BlockedNumberContract { /** * Returns {@code true} if {@code phoneNumber} is blocked taking - * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services have - * not been contacted recently, this method is equivalent to - * {@link #isBlocked(Context, String)}. + * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services + * have not been contacted recently and enhanced call blocking not been enabled, this + * method is equivalent to {@link #isBlocked(Context, String)}. + * + * @param context the context of the caller. + * @param phoneNumber the number to check. + * @param extras the extra attribute of the number. + * @return {@code true} if should block the number. {@code false} otherwise. */ - public static boolean shouldSystemBlockNumber(Context context, String phoneNumber) { + public static boolean shouldSystemBlockNumber(Context context, String phoneNumber, + Bundle extras) { final Bundle res = context.getContentResolver().call( - AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, null); + AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, extras); return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false); } @@ -363,9 +410,62 @@ public class BlockedNumberContract { } /** - * Represents the current status of {@link #shouldSystemBlockNumber(Context, String)}. If - * emergency services have been contacted recently, {@link #isSuppressed} is {@code true}, - * and blocking is disabled until the timestamp {@link #untilTimestampMillis}. + * Check whether should show the emergency call notification. + * + * @param context the context of the caller. + * @return {@code true} if should show emergency call notification. {@code false} otherwise. + */ + public static boolean shouldShowEmergencyCallNotification(Context context) { + final Bundle res = context.getContentResolver().call( + AUTHORITY_URI, METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION, null, null); + return res != null && res.getBoolean(RES_SHOW_EMERGENCY_CALL_NOTIFICATION, false); + } + + /** + * Check whether the enhanced block setting is enabled. + * + * @param context the context of the caller. + * @param key the key of the setting to check, can be + * {@link #ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED} + * {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE} + * {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE} + * {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN} + * {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING} + * @return {@code true} if the setting is enabled. {@code false} otherwise. + */ + public static boolean getEnhancedBlockSetting(Context context, String key) { + Bundle extras = new Bundle(); + extras.putString(EXTRA_ENHANCED_SETTING_KEY, key); + final Bundle res = context.getContentResolver().call( + AUTHORITY_URI, METHOD_GET_ENHANCED_BLOCK_SETTING, null, extras); + return res != null && res.getBoolean(RES_ENHANCED_SETTING_IS_ENABLED, false); + } + + /** + * Set the enhanced block setting enabled status. + * + * @param context the context of the caller. + * @param key the key of the setting to set, can be + * {@link #ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED} + * {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE} + * {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE} + * {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN} + * {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING} + * @param value the enabled statue of the setting to set. + */ + public static void setEnhancedBlockSetting(Context context, String key, boolean value) { + Bundle extras = new Bundle(); + extras.putString(EXTRA_ENHANCED_SETTING_KEY, key); + extras.putBoolean(EXTRA_ENHANCED_SETTING_VALUE, value); + context.getContentResolver().call(AUTHORITY_URI, METHOD_SET_ENHANCED_BLOCK_SETTING, + null, extras); + } + + /** + * Represents the current status of + * {@link #shouldSystemBlockNumber(Context, String, Bundle)}. If emergency services + * have been contacted recently, {@link #isSuppressed} is {@code true}, and blocking + * is disabled until the timestamp {@link #untilTimestampMillis}. */ public static class BlockSuppressionStatus { public final boolean isSuppressed; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index fea9972c662cf87033ce4c97ca53015bc49e44a9..8bd3847c42f29758c1428747393389078e31b074 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -83,7 +83,6 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.MemoryIntArray; -import android.util.StatsLog; import android.view.textservice.TextServicesManager; import com.android.internal.annotations.GuardedBy; @@ -1715,6 +1714,34 @@ public final class Settings { }) public @interface ResetMode{} + + /** + * User has not started setup personalization. + * @hide + */ + public static final int USER_SETUP_PERSONALIZATION_NOT_STARTED = 0; + + /** + * User has not yet completed setup personalization. + * @hide + */ + public static final int USER_SETUP_PERSONALIZATION_STARTED = 1; + + /** + * User has completed setup personalization. + * @hide + */ + public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + USER_SETUP_PERSONALIZATION_NOT_STARTED, + USER_SETUP_PERSONALIZATION_STARTED, + USER_SETUP_PERSONALIZATION_COMPLETE + }) + public @interface UserSetupPersonalization {} + /** * Activity Extra: Number of certificates *

    @@ -1914,11 +1941,7 @@ public final class Settings { arg.putBoolean(CALL_METHOD_MAKE_DEFAULT_KEY, true); } IContentProvider cp = mProviderHolder.getProvider(cr); - String prevValue = getStringForUser(cr, name, userHandle); cp.call(cr.getPackageName(), mCallSetCommand, name, arg); - String newValue = getStringForUser(cr, name, userHandle); - StatsLog.write(StatsLog.SETTING_CHANGED, name, value, newValue, prevValue, tag, - makeDefault, userHandle); } catch (RemoteException e) { Log.w(TAG, "Can't set key " + name + " in " + mUri, e); return false; @@ -3727,7 +3750,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"; @@ -5440,6 +5463,15 @@ public final class Settings { @TestApi public static final String USER_SETUP_COMPLETE = "user_setup_complete"; + /** + * The current state of device personalization. + * + * @hide + * @see UserSetupPersonalization + */ + public static final String USER_SETUP_PERSONALIZATION_STATE = + "user_setup_personalization_state"; + /** * 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 @@ -8752,21 +8784,6 @@ public final class Settings { public static final String LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST = "location_background_throttle_package_whitelist"; - /** - * The interval in milliseconds at which wifi scan requests will be throttled when they are - * coming from the background. - * @hide - */ - public static final String WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS = - "wifi_scan_background_throttle_interval_ms"; - - /** - * Packages that are whitelisted to be exempt for wifi background throttling. - * @hide - */ - public static final String WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST = - "wifi_scan_background_throttle_package_whitelist"; - /** * Whether TV will switch to MHL port when a mobile device is plugged in. * (0 = false, 1 = true) @@ -9519,6 +9536,12 @@ public final class Settings { public static final String BLE_SCAN_LOW_LATENCY_INTERVAL_MS = "ble_scan_low_latency_interval_ms"; + /** + * The mode that BLE scanning clients will be moved to when in the background. + * @hide + */ + public static final String BLE_SCAN_BACKGROUND_MODE = "ble_scan_background_mode"; + /** * Used to save the Wifi_ON state prior to tethering. * This state will be checked to restore Wifi after @@ -10270,31 +10293,6 @@ public final class Settings { public static final String BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS = "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: - * - *

    -         * 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)
    -         * 
    - * @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: @@ -10323,6 +10321,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: + * + *
    +         * 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)
    +         * 
    + * @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. @@ -10377,6 +10400,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 +10632,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 +10643,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 = @@ -10659,13 +10693,21 @@ public final class Settings { = "wifi_on_when_proxy_disconnected"; /** - * Whether or not to enable Time Only Mode for watch type devices. - * Type: int (0 for false, 1 for true) - * Default: 0 + * Time Only Mode specific settings. + * This is encoded as a key=value list, separated by commas. Ex: "foo=1,bar=true" + * + * The following keys are supported: + * + *
    +         * enabled                  (boolean)
    +         * disable_tilt_to_wake     (boolean)
    +         * disable_touch_to_wake    (boolean)
    +         * 
    + * Type: string * @hide */ - public static final String TIME_ONLY_MODE_ENABLED - = "time_only_mode_enabled"; + public static final String TIME_ONLY_MODE_CONSTANTS + = "time_only_mode_constants"; /** * Whether or not Network Watchlist feature is enabled. @@ -11194,6 +11236,20 @@ public final class Settings { */ public static final String ZEN_MODE_CONFIG_ETAG = "zen_mode_config_etag"; + /** + * 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. + * @hide + */ + public static final String ZEN_DURATION = "zen_duration"; + + private static final Validator ZEN_DURATION_VALIDATOR = ANY_INTEGER_VALIDATOR; + + /** @hide */ public static final int ZEN_DURATION_PROMPT = -1; + /** @hide */ public static final int ZEN_DURATION_FOREVER = 0; + /** * Defines global heads up toggle. One of HEADS_UP_OFF, HEADS_UP_ON. * @@ -11510,7 +11566,14 @@ public final class Settings { /** * The packages whitelisted to be run in autofill compatibility mode. The list - * of packages is ":" colon delimited. + * of packages is {@code ":"} colon delimited, and each entry has the name of the + * package and an optional list of url bar resource ids (the list is delimited by + * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited). + * + *

    For example, a list with 3 packages {@code p1}, {@code p2}, and {@code p3}, where + * package {@code p1} have one id ({@code url_bar}, {@code p2} has none, and {@code p3 } + * have 2 ids {@code url_foo} and {@code url_bas}) would be + * {@code p1[url_bar]:p2:p3[url_foo,url_bas]} * * @hide */ @@ -11528,6 +11591,24 @@ public final class Settings { public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions"; + /** + * Timeout for a single {@link android.media.soundtrigger.SoundTriggerDetectionService} + * operation (in ms). + * + * @hide + */ + public static final String SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT = + "sound_trigger_detection_service_op_timeout"; + + /** + * Maximum number of {@link android.media.soundtrigger.SoundTriggerDetectionService} + * operations per day. + * + * @hide + */ + public static final String MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY = + "max_sound_trigger_detection_service_ops_per_day"; + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. @@ -11568,7 +11649,8 @@ public final class Settings { BLUETOOTH_ON, PRIVATE_DNS_MODE, PRIVATE_DNS_SPECIFIER, - SOFT_AP_TIMEOUT_ENABLED + SOFT_AP_TIMEOUT_ENABLED, + ZEN_DURATION, }; /** @@ -11609,6 +11691,7 @@ public final class Settings { VALIDATORS.put(WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON, WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR); VALIDATORS.put(APP_AUTO_RESTRICTION_ENABLED, APP_AUTO_RESTRICTION_ENABLED_VALIDATOR); + VALIDATORS.put(ZEN_DURATION, ZEN_DURATION_VALIDATOR); } /** @@ -12261,6 +12344,16 @@ public final class Settings { public static final String ZRAM_ENABLED = "zram_enabled"; + /** + * Whether we have enable CPU frequency scaling for this device. + * For Wear, default is disable. + * + * The value is "1" for enable, "0" for disable. + * @hide + */ + public static final String CPU_SCALING_ENABLED = + "cpu_frequency_scaling_enabled"; + /** * Configuration flags for smart replies in notifications. * This is encoded as a key=value list, separated by commas. Ex: @@ -12304,6 +12397,28 @@ public final class Settings { * @hide */ public static final String SHOW_ZEN_UPGRADE_NOTIFICATION = "show_zen_upgrade_notification"; + + /** + * Backup and restore agent timeout parameters. + * These parameters are represented by a comma-delimited key-value list. + * + * The following strings are supported as keys: + *

    +         *     kv_backup_agent_timeout_millis         (long)
    +         *     full_backup_agent_timeout_millis       (long)
    +         *     shared_backup_agent_timeout_millis     (long)
    +         *     restore_agent_timeout_millis           (long)
    +         *     restore_agent_finished_timeout_millis  (long)
    +         * 
    + * + * They map to milliseconds represented as longs. + * + * Ex: "kv_backup_agent_timeout_millis=30000,full_backup_agent_timeout_millis=300000" + * + * @hide + */ + public static final String BACKUP_AGENT_TIMEOUT_PARAMETERS = + "backup_agent_timeout_parameters"; } /** diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java index c568b6fbe0c48bb46e71e2d8fd1c1e699340de33..140336e93357ffd75a0f6e0487fdd4985179d009 100644 --- a/core/java/android/provider/VoicemailContract.java +++ b/core/java/android/provider/VoicemailContract.java @@ -49,7 +49,8 @@ import java.util.List; * * *

    The minimum permission needed to access this content provider is - * {@link android.Manifest.permission#ADD_VOICEMAIL} + * {@link android.Manifest.permission#ADD_VOICEMAIL} or carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). * *

    Voicemails are inserted by what is called as a "voicemail source" * application, which is responsible for syncing voicemail data between a remote diff --git a/core/java/android/se/omapi/Session.java b/core/java/android/se/omapi/Session.java index 19a018ee01bbcf6a71fab4a84bfa8dbed2771661..3d8b74b51c4c672689fedafad9c25cf00c0b384a 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/ConfirmationDialog.java b/core/java/android/security/ConfirmationDialog.java index f6127e184139789f5df3d928efe50cdbcf9c6325..1697106c378221b1feccb6d6ed68d9fdbd943e56 100644 --- a/core/java/android/security/ConfirmationDialog.java +++ b/core/java/android/security/ConfirmationDialog.java @@ -227,12 +227,32 @@ public class ConfirmationDialog { return uiOptionsAsFlags; } + private boolean isAccessibilityServiceRunning() { + boolean serviceRunning = false; + try { + ContentResolver contentResolver = mContext.getContentResolver(); + int a11yEnabled = Settings.Secure.getInt(contentResolver, + Settings.Secure.ACCESSIBILITY_ENABLED); + if (a11yEnabled == 1) { + serviceRunning = true; + } + } catch (SettingNotFoundException e) { + Log.w(TAG, "Unexpected SettingNotFoundException"); + e.printStackTrace(); + } + return serviceRunning; + } + /** * Requests a confirmation prompt to be presented to the user. * * When the prompt is no longer being presented, one of the methods in * {@link ConfirmationCallback} is called on the supplied callback object. * + * Confirmation dialogs may not be available when accessibility services are running so this + * may fail with a {@link ConfirmationNotAvailableException} exception even if + * {@link #isSupported} returns {@code true}. + * * @param executor the executor identifying the thread that will receive the callback. * @param callback the callback to use when the dialog is done showing. * @throws IllegalArgumentException if the prompt text is too long or malfomed. @@ -245,6 +265,9 @@ public class ConfirmationDialog { if (mCallback != null) { throw new ConfirmationAlreadyPresentingException(); } + if (isAccessibilityServiceRunning()) { + throw new ConfirmationNotAvailableException(); + } mCallback = callback; mExecutor = executor; diff --git a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java index aa09f10de0705c774396dd233917d1348d501ae0..3d3b6d56557715596dc1563aab2b7d06c3b7d625 100644 --- a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java +++ b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java @@ -215,8 +215,8 @@ public final class KeyChainProtectionParams implements Parcelable { /** * Creates a new {@link KeyChainProtectionParams} instance. - * The instance will include default values, if {@link setSecret} - * or {@link setUserSecretType} were not called. + * The instance will include default values, if {@link #setSecret} + * or {@link #setUserSecretType} were not called. * * @return new instance * @throws NullPointerException if some required fields were not set. diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java index 4580c47ac3c3a7bc59764f8b53c2824dd1c4819b..00f54e16863d92982e46c59cacf6203345e3686d 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 mKeyChainProtectionParams; private List 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/security/keystore/recovery/KeyDerivationParams.java b/core/java/android/security/keystore/recovery/KeyDerivationParams.java index fc909a0aac9e4b95cbb58a9b246299e8fb02f040..428eaaa0079e4308f1b598b360bd6d2e164a6fa4 100644 --- a/core/java/android/security/keystore/recovery/KeyDerivationParams.java +++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.java @@ -30,32 +30,33 @@ import java.lang.annotation.RetentionPolicy; /** * Collection of parameters which define a key derivation function. - * Currently only supports salted SHA-256 + * Currently only supports salted SHA-256. * * @hide */ @SystemApi public final class KeyDerivationParams implements Parcelable { private final int mAlgorithm; - private byte[] mSalt; + private final byte[] mSalt; + private final int mDifficulty; /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"ALGORITHM_"}, value = {ALGORITHM_SHA256, ALGORITHM_ARGON2ID}) + @IntDef(prefix = {"ALGORITHM_"}, value = {ALGORITHM_SHA256, ALGORITHM_SCRYPT}) public @interface KeyDerivationAlgorithm { } /** - * Salted SHA256 + * Salted SHA256. */ public static final int ALGORITHM_SHA256 = 1; /** - * Argon2ID + * SCRYPT. + * * @hide */ - // TODO: add Argon2ID support. - public static final int ALGORITHM_ARGON2ID = 2; + public static final int ALGORITHM_SCRYPT = 2; /** * Creates instance of the class to to derive key using salted SHA256 hash. @@ -64,13 +65,31 @@ public final class KeyDerivationParams implements Parcelable { return new KeyDerivationParams(ALGORITHM_SHA256, salt); } + /** + * Creates instance of the class to to derive key using the password hashing algorithm SCRYPT. + * + * @hide + */ + public static KeyDerivationParams createScryptParams(@NonNull byte[] salt, int difficulty) { + return new KeyDerivationParams(ALGORITHM_SCRYPT, salt, difficulty); + } + /** * @hide */ // TODO: Make private once legacy API is removed public KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) { + this(algorithm, salt, /*difficulty=*/ 0); + } + + /** + * @hide + */ + KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt, + int difficulty) { mAlgorithm = algorithm; mSalt = Preconditions.checkNotNull(salt); + mDifficulty = difficulty; } /** @@ -87,6 +106,15 @@ public final class KeyDerivationParams implements Parcelable { return mSalt; } + /** + * Gets hashing difficulty. + * + * @hide + */ + public int getDifficulty() { + return mDifficulty; + } + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public KeyDerivationParams createFromParcel(Parcel in) { @@ -102,6 +130,7 @@ public final class KeyDerivationParams implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(mAlgorithm); out.writeByteArray(mSalt); + out.writeInt(mDifficulty); } /** @@ -110,6 +139,7 @@ public final class KeyDerivationParams implements Parcelable { protected KeyDerivationParams(Parcel in) { mAlgorithm = in.readInt(); mSalt = in.createByteArray(); + mDifficulty = in.readInt(); } @Override diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java index 48813757aaa895067adcc31e94cf600b0af61e40..7523afdf80414a0e7dc8eb23015a3848061ce0b5 100644 --- a/core/java/android/security/keystore/recovery/RecoveryController.java +++ b/core/java/android/security/keystore/recovery/RecoveryController.java @@ -33,6 +33,7 @@ import com.android.internal.widget.ILockSettings; import java.security.Key; import java.security.UnrecoverableKeyException; +import java.security.cert.CertPath; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.List; @@ -156,6 +157,7 @@ public class RecoveryController { /** * Gets a new instance of the class. */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public static RecoveryController getInstance(Context context) { ILockSettings lockSettings = ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings")); @@ -245,8 +247,6 @@ public class RecoveryController { * @return Data necessary to recover keystore or {@code null} if snapshot is not available. * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery * service. - * - * @hide */ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public @Nullable KeyChainSnapshot getKeyChainSnapshot() @@ -288,7 +288,7 @@ public class RecoveryController { /** * Server parameters used to generate new recovery key blobs. This value will be included in * {@code KeyChainSnapshot.getEncryptedRecoveryKeyBlob()}. The same value must be included - * in vaultParams {@link #startRecoverySession} + * in vaultParams {@link RecoverySession#start(CertPath, byte[], byte[], List)}. * * @param serverParams included in recovery key blob. * @see #getRecoveryData @@ -310,6 +310,7 @@ public class RecoveryController { * @deprecated Use {@link #getAliases()}. */ @Deprecated + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public List getAliases(@Nullable String packageName) throws InternalRecoveryServiceException { return getAliases(); @@ -318,6 +319,7 @@ public class RecoveryController { /** * Returns a list of aliases of keys belonging to the application. */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public List getAliases() throws InternalRecoveryServiceException { try { Map allStatuses = mBinder.getRecoveryStatus(); @@ -367,6 +369,7 @@ public class RecoveryController { * @deprecated Use {@link #getRecoveryStatus(String)}. */ @Deprecated + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public int getRecoveryStatus(String packageName, String alias) throws InternalRecoveryServiceException { return getRecoveryStatus(alias); @@ -385,6 +388,7 @@ public class RecoveryController { * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery * service. */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public int getRecoveryStatus(String alias) throws InternalRecoveryServiceException { try { Map allStatuses = mBinder.getRecoveryStatus(); @@ -410,6 +414,7 @@ public class RecoveryController { * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery * service. */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void setRecoverySecretTypes( @NonNull @KeyChainProtectionParams.UserSecretType int[] secretTypes) throws InternalRecoveryServiceException { @@ -431,6 +436,7 @@ public class RecoveryController { * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery * service. */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public @NonNull @KeyChainProtectionParams.UserSecretType int[] getRecoverySecretTypes() throws InternalRecoveryServiceException { try { @@ -452,6 +458,7 @@ public class RecoveryController { * service. */ @NonNull + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public @KeyChainProtectionParams.UserSecretType int[] getPendingRecoverySecretTypes() throws InternalRecoveryServiceException { try { @@ -474,6 +481,7 @@ public class RecoveryController { * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery * service. */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void recoverySecretAvailable(@NonNull KeyChainProtectionParams recoverySecret) throws InternalRecoveryServiceException { try { @@ -498,6 +506,7 @@ public class RecoveryController { * to generate recoverable keys, as the snapshots are encrypted using a key derived from the * lock screen. */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public byte[] generateAndStoreKey(@NonNull String alias, byte[] account) throws InternalRecoveryServiceException, LockScreenRequiredException { try { @@ -512,11 +521,11 @@ public class RecoveryController { } } - // TODO: Unhide the following APIs, generateKey(), importKey(), and getKey() /** * @deprecated Use {@link #generateKey(String)}. */ @Deprecated + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public Key generateKey(@NonNull String alias, byte[] account) throws InternalRecoveryServiceException, LockScreenRequiredException { return generateKey(alias); @@ -530,6 +539,7 @@ public class RecoveryController { * @throws LockScreenRequiredException if the user does not have a lock screen set. A lock * screen is required to generate recoverable keys. */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public Key generateKey(@NonNull String alias) throws InternalRecoveryServiceException, LockScreenRequiredException { try { @@ -562,8 +572,8 @@ public class RecoveryController { * @throws LockScreenRequiredException if the user does not have a lock screen set. A lock * screen is required to generate recoverable keys. * - * @hide */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public Key importKey(@NonNull String alias, byte[] keyBytes) throws InternalRecoveryServiceException, LockScreenRequiredException { try { @@ -595,8 +605,8 @@ public class RecoveryController { * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery * service. * @throws UnrecoverableKeyException if key is permanently invalidated or not found. - * @hide */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public @Nullable Key getKey(@NonNull String alias) throws InternalRecoveryServiceException, UnrecoverableKeyException { try { @@ -622,6 +632,7 @@ public class RecoveryController { * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery * service. */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void removeKey(@NonNull String alias) throws InternalRecoveryServiceException { try { mBinder.removeKey(alias); @@ -637,6 +648,7 @@ public class RecoveryController { * *

    A recovery session is required to restore keys from a remote store. */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public RecoverySession createRecoverySession() { return RecoverySession.newInstance(this); } diff --git a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java new file mode 100644 index 0000000000000000000000000000000000000000..27c652278512a376095bd4d86742e6e9582b3ac0 --- /dev/null +++ b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java @@ -0,0 +1,100 @@ +/* + * 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.security.keystore.recovery; + +import static android.security.keystore.recovery.X509CertificateParsingUtils.decodeBase64Cert; + +import android.util.ArrayMap; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Map; + +/** + * Trusted root certificates for use by the + * {@link android.security.keystore.recovery.RecoveryController}. These certificates are used to + * verify the public keys of remote secure hardware modules. This is to prevent AOSP backing up keys + * to untrusted devices. + * + * @hide + */ +public class TrustedRootCertificates { + + public static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS = + "GoogleCloudKeyVaultServiceV1"; + + private static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64 = "" + + "MIIFJjCCAw6gAwIBAgIJAIobXsJlzhNdMA0GCSqGSIb3DQEBDQUAMCAxHjAcBgNV" + + "BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAyMDIxOTM5MTRaFw0zODAx" + + "MjgxOTM5MTRaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCAiIw" + + "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2OT5i40/H7LINg/lq/0G0hR65P" + + "Q4Mud3OnuVt6UIYV2T18+v6qW1yJd5FcnND/ZKPau4aUAYklqJuSVjOXQD0BjgS2" + + "98Xa4dSn8Ci1rUR+5tdmrxqbYUdT2ZvJIUMMR6fRoqi+LlAbKECrV+zYQTyLU68w" + + "V66hQpAButjJKiZzkXjmKLfJ5IWrNEn17XM988rk6qAQn/BYCCQGf3rQuJeksGmA" + + "N1lJOwNYxmWUyouVwqwZthNEWqTuEyBFMkAT+99PXW7oVDc7oU5cevuihxQWNTYq" + + "viGB8cck6RW3cmqrDSaJF/E+N0cXFKyYC7FDcggt6k3UrxNKTuySdDEa8+2RTQqU" + + "Y9npxBlQE+x9Ig56OI1BG3bSBsGdPgjpyHadZeh2tgk+oqlGsSsum24YxaxuSysT" + + "Qfcu/XhyfUXavfmGrBOXerTzIl5oBh/F5aHTV85M2tYEG0qsPPvSpZAWtdJ/2rca" + + "OxvhwOL+leZKr8McjXVR00lBsRuKXX4nTUMwya09CO3QHFPFZtZvqjy2HaMOnVLQ" + + "I6b6dHEfmsHybzVOe3yPEoFQSU9UhUdmi71kwwoanPD3j9fJHmXTx4PzYYBRf1ZE" + + "o+uPgMPk7CDKQFZLjnR40z1uzu3O8aZ3AKZzP+j7T4XQKJLQLmllKtPgLgNdJyib" + + "2Glg7QhXH/jBTL6hAgMBAAGjYzBhMB0GA1UdDgQWBBSbZfrqOYH54EJpkdKMZjMc" + + "z/Hp+DAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DAPBgNVHRMBAf8E" + + "BTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQ0FAAOCAgEAKh9nm/vW" + + "glMWp3vcCwWwJW286ecREDlI+CjGh5h+f2N4QRrXd/tKE3qQJWCqGx8sFfIUjmI7" + + "KYdsC2gyQ2cA2zl0w7pB2QkuqE6zVbnh1D17Hwl19IMyAakFaM9ad4/EoH7oQmqX" + + "nF/f5QXGZw4kf1HcgKgoCHWXjqR8MqHOcXR8n6WFqxjzJf1jxzi6Yo2dZ7PJbnE6" + + "+kHIJuiCpiHL75v5g1HM41gT3ddFFSrn88ThNPWItT5Z8WpFjryVzank2Yt02LLl" + + "WqZg9IC375QULc5B58NMnaiVJIDJQ8zoNgj1yaxqtUMnJX570lotO2OXe4ec9aCQ" + + "DIJ84YLM/qStFdeZ9416E80dchskbDG04GuVJKlzWjxAQNMRFhyaPUSBTLLg+kwP" + + "t9+AMmc+A7xjtFQLZ9fBYHOBsndJOmeSQeYeckl+z/1WQf7DdwXn/yijon7mxz4z" + + "cCczfKwTJTwBh3wR5SQr2vQm7qaXM87qxF8PCAZrdZaw5I80QwkgTj0WTZ2/GdSw" + + "d3o5SyzzBAjpwtG+4bO/BD9h9wlTsHpT6yWOZs4OYAKU5ykQrncI8OyavMggArh3" + + "/oM58v0orUWINtIc2hBlka36PhATYQiLf+AiWKnwhCaaHExoYKfQlMtXBodNvOK8" + + "xqx69x05q/qbHKEcTHrsss630vxrp1niXvA="; + + /** + * The X509 certificate of the trusted root CA cert for the recoverable key store service. + * + * TODO: Change it to the production certificate root CA before the final launch. + */ + private static final X509Certificate GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_CERTIFICATE = + parseGoogleCloudKeyVaultServiceV1Certificate(); + + private static final int NUMBER_OF_ROOT_CERTIFICATES = 1; + + /** + * Returns all available root certificates, keyed by alias. + */ + public static Map listRootCertificates() { + ArrayMap certificates = + new ArrayMap<>(NUMBER_OF_ROOT_CERTIFICATES); + certificates.put( + GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS, + GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_CERTIFICATE); + return certificates; + } + + private static X509Certificate parseGoogleCloudKeyVaultServiceV1Certificate() { + try { + return decodeBase64Cert(GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64); + } catch (CertificateException e) { + // Should not happen + throw new RuntimeException(e); + } + } +} diff --git a/core/java/android/security/keystore/recovery/X509CertificateParsingUtils.java b/core/java/android/security/keystore/recovery/X509CertificateParsingUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..fa72c836b5dfe573cb97e2aab17c6b328b356e78 --- /dev/null +++ b/core/java/android/security/keystore/recovery/X509CertificateParsingUtils.java @@ -0,0 +1,82 @@ +/* + * Copyright 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.security.keystore.recovery; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Base64; + +/** + * Static helper methods for decoding {@link X509Certificate} instances. + * + * @hide + */ +public class X509CertificateParsingUtils { + private static final String CERT_FORMAT = "X.509"; + + /** + * Decodes an {@link X509Certificate} encoded as a base-64 string. + */ + public static X509Certificate decodeBase64Cert(String string) throws CertificateException { + try { + return decodeCert(decodeBase64(string)); + } catch (IllegalArgumentException e) { + throw new CertificateException(e); + } + } + + /** + * Decodes a base-64 string. + * + * @throws IllegalArgumentException if not a valid base-64 string. + */ + private static byte[] decodeBase64(String string) { + return Base64.getDecoder().decode(string); + } + + /** + * Decodes a byte array containing an encoded X509 certificate. + * + * @param certBytes the byte array containing the encoded X509 certificate + * @return the decoded X509 certificate + * @throws CertificateException if any parsing error occurs + */ + private static X509Certificate decodeCert(byte[] certBytes) throws CertificateException { + return decodeCert(new ByteArrayInputStream(certBytes)); + } + + /** + * Decodes an X509 certificate from an {@code InputStream}. + * + * @param inStream the input stream containing the encoded X509 certificate + * @return the decoded X509 certificate + * @throws CertificateException if any parsing error occurs + */ + private static X509Certificate decodeCert(InputStream inStream) throws CertificateException { + CertificateFactory certFactory; + try { + certFactory = CertificateFactory.getInstance(CERT_FORMAT); + } catch (CertificateException e) { + // Should not happen, as X.509 is mandatory for all providers. + throw new RuntimeException(e); + } + return (X509Certificate) certFactory.generateCertificate(inStream); + } +} diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java index 0c5d8bd6a83a8b22a194e997273fccc423e2736b..41e41819526faf72f7638d39a20b5aa5f7c3895f 100644 --- a/core/java/android/service/autofill/AutofillService.java +++ b/core/java/android/service/autofill/AutofillService.java @@ -528,7 +528,6 @@ import android.view.autofill.AutofillValue; * <compatibility-package android:name="foo.bar.baz" android:maxLongVersionCode="1000000000"/> * </autofill-service> */ -// TODO(b/70407264): add code snippets to field classification ??? public abstract class AutofillService extends Service { private static final String TAG = "AutofillService"; diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java index 70c4ec07ee4eb33916bae85f083feaac629cb4a4..de234559d53e1265c66600aee6d2c0629fa809b6 100644 --- a/core/java/android/service/autofill/AutofillServiceInfo.java +++ b/core/java/android/service/autofill/AutofillServiceInfo.java @@ -32,7 +32,6 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.Log; -import android.util.Pair; import android.util.Xml; import com.android.internal.R; @@ -79,7 +78,7 @@ public final class AutofillServiceInfo { private final String mSettingsActivity; @Nullable - private final ArrayMap> mCompatibilityPackages; + private final ArrayMap mCompatibilityPackages; public AutofillServiceInfo(Context context, ComponentName comp, int userHandle) throws PackageManager.NameNotFoundException { @@ -117,7 +116,7 @@ public final class AutofillServiceInfo { } String settingsActivity = null; - ArrayMap> compatibilityPackages = null; + ArrayMap compatibilityPackages = null; try { final Resources resources = context.getPackageManager().getResourcesForApplication( @@ -153,10 +152,9 @@ public final class AutofillServiceInfo { mCompatibilityPackages = compatibilityPackages; } - private ArrayMap> parseCompatibilityPackages(XmlPullParser parser, - Resources resources) - throws IOException, XmlPullParserException { - ArrayMap> compatibilityPackages = null; + private ArrayMap parseCompatibilityPackages(XmlPullParser parser, + Resources resources) throws IOException, XmlPullParserException { + ArrayMap compatibilityPackages = null; final int outerDepth = parser.getDepth(); int type; @@ -200,13 +198,18 @@ public final class AutofillServiceInfo { } else { maxVersionCode = Long.MAX_VALUE; } - final String urlBarResourceId = cpAttributes.getString( - R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId); + if (true) { // TODO(b/74445943): remove block after P DP2 is branched + final String urlBarResourceId = cpAttributes.getString( + R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId); + if (urlBarResourceId != null) { + Log.e(TAG, "Service is using deprecated attribute 'urlBarResourceId'"); + } + } if (compatibilityPackages == null) { compatibilityPackages = new ArrayMap<>(); } - compatibilityPackages.put(name, new Pair<>(maxVersionCode, urlBarResourceId)); + compatibilityPackages.put(name, maxVersionCode); } finally { XmlUtils.skipCurrentTag(parser); if (cpAttributes != null) { @@ -228,23 +231,10 @@ public final class AutofillServiceInfo { return mSettingsActivity; } - public ArrayMap> getCompatibilityPackages() { + public ArrayMap getCompatibilityPackages() { return mCompatibilityPackages; } - /** - * Gets the resource id of the URL bar for a package. Used in compat mode - */ - // TODO: return a list of strings instead - @Nullable - public String getUrlBarResourceId(String packageName) { - if (mCompatibilityPackages == null) { - return null; - } - final Pair pair = mCompatibilityPackages.get(packageName); - return pair == null ? null : pair.second; - } - @Override public String toString() { final StringBuilder builder = new StringBuilder(); diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java index a1dd1f846515841ab4498146d85fd88fb8742007..55aecddf8365e17176a06d71a1f6d887cf451678 100644 --- a/core/java/android/service/autofill/UserData.java +++ b/core/java/android/service/autofill/UserData.java @@ -169,17 +169,15 @@ public final class UserData implements Parcelable { * @param categoryId string used to identify the category the value is associated with. * * @throws IllegalArgumentException if any of the following occurs: - *

      + *
        *
      • {@code id} is empty
      • *
      • {@code categoryId} is empty
      • *
      • {@code value} is empty
      • *
      • the length of {@code value} is lower than {@link UserData#getMinValueLength()}
      • *
      • the length of {@code value} is higher than * {@link UserData#getMaxValueLength()}
      • - *
    - * + * */ - // TODO(b/70407264): ignore entry instead of throwing exception when settings changed public Builder(@NonNull String id, @NonNull String value, @NonNull String categoryId) { mId = checkNotEmpty("id", id); checkNotEmpty("categoryId", categoryId); @@ -222,26 +220,25 @@ public final class UserData implements Parcelable { * @param categoryId string used to identify the category the value is associated with. * * @throws IllegalStateException if: - *
      + *
        *
      • {@link #build()} already called
      • *
      • the {@code value} has already been added
      • *
      • the number of unique {@code categoryId} values added so far is more than * {@link UserData#getMaxCategoryCount()}
      • *
      • the number of {@code values} added so far is is more than * {@link UserData#getMaxUserDataSize()}
      • - *
    + * * * @throws IllegalArgumentException if any of the following occurs: - *
      + *
        *
      • {@code id} is empty
      • *
      • {@code categoryId} is empty
      • *
      • {@code value} is empty
      • *
      • the length of {@code value} is lower than {@link UserData#getMinValueLength()}
      • *
      • the length of {@code value} is higher than * {@link UserData#getMaxValueLength()}
      • - *
    + * */ - // TODO(b/70407264): ignore entry instead of throwing exception when settings changed public Builder add(@NonNull String value, @NonNull String categoryId) { throwIfDestroyed(); checkNotEmpty("categoryId", categoryId); diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index ea10ae7b380808904b1e9e5ac1a1f80f107d8fa6..3726e66d01f95b551ef2f2ccc4052eb3bb025f58 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -1418,6 +1418,7 @@ public abstract class NotificationListenerService extends Service { private ArrayList mSnoozeCriteria; private boolean mShowBadge; private @UserSentiment int mUserSentiment = USER_SENTIMENT_NEUTRAL; + private boolean mHidden; public Ranking() {} @@ -1556,6 +1557,16 @@ public abstract class NotificationListenerService extends Service { return mShowBadge; } + /** + * Returns whether the app that posted this notification is suspended, so this notification + * should be hidden. + * + * @return true if the notification should be hidden, false otherwise. + */ + public boolean isSuspended() { + return mHidden; + } + /** * @hide */ @@ -1565,7 +1576,7 @@ public abstract class NotificationListenerService extends Service { CharSequence explanation, String overrideGroupKey, NotificationChannel channel, ArrayList overridePeople, ArrayList snoozeCriteria, boolean showBadge, - int userSentiment) { + int userSentiment, boolean hidden) { mKey = key; mRank = rank; mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW; @@ -1580,6 +1591,7 @@ public abstract class NotificationListenerService extends Service { mSnoozeCriteria = snoozeCriteria; mShowBadge = showBadge; mUserSentiment = userSentiment; + mHidden = hidden; } /** @@ -1628,6 +1640,7 @@ public abstract class NotificationListenerService extends Service { private ArrayMap> mSnoozeCriteria; private ArrayMap mShowBadge; private ArrayMap mUserSentiment; + private ArrayMap mHidden; private RankingMap(NotificationRankingUpdate rankingUpdate) { mRankingUpdate = rankingUpdate; @@ -1656,7 +1669,7 @@ public abstract class NotificationListenerService extends Service { getVisibilityOverride(key), getSuppressedVisualEffects(key), getImportance(key), getImportanceExplanation(key), getOverrideGroupKey(key), getChannel(key), getOverridePeople(key), getSnoozeCriteria(key), - getShowBadge(key), getUserSentiment(key)); + getShowBadge(key), getUserSentiment(key), getHidden(key)); return rank >= 0; } @@ -1784,6 +1797,16 @@ public abstract class NotificationListenerService extends Service { ? Ranking.USER_SENTIMENT_NEUTRAL : userSentiment.intValue(); } + private boolean getHidden(String key) { + synchronized (this) { + if (mHidden == null) { + buildHiddenLocked(); + } + } + Boolean hidden = mHidden.get(key); + return hidden == null ? false : hidden.booleanValue(); + } + // Locked by 'this' private void buildRanksLocked() { String[] orderedKeys = mRankingUpdate.getOrderedKeys(); @@ -1892,6 +1915,15 @@ public abstract class NotificationListenerService extends Service { } } + // Locked by 'this' + private void buildHiddenLocked() { + Bundle hidden = mRankingUpdate.getHidden(); + mHidden = new ArrayMap<>(hidden.size()); + for (String key : hidden.keySet()) { + mHidden.put(key, hidden.getBoolean(key)); + } + } + // ----------- Parcelable @Override diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java index 6d51db096a27c050c87655f85544e130445b7989..00c47ec0ee893b740312f8b8e2b5b2f161fe9f9c 100644 --- a/core/java/android/service/notification/NotificationRankingUpdate.java +++ b/core/java/android/service/notification/NotificationRankingUpdate.java @@ -36,12 +36,13 @@ public class NotificationRankingUpdate implements Parcelable { private final Bundle mSnoozeCriteria; private final Bundle mShowBadge; private final Bundle mUserSentiment; + private final Bundle mHidden; public NotificationRankingUpdate(String[] keys, String[] interceptedKeys, Bundle visibilityOverrides, Bundle suppressedVisualEffects, int[] importance, Bundle explanation, Bundle overrideGroupKeys, Bundle channels, Bundle overridePeople, Bundle snoozeCriteria, - Bundle showBadge, Bundle userSentiment) { + Bundle showBadge, Bundle userSentiment, Bundle hidden) { mKeys = keys; mInterceptedKeys = interceptedKeys; mVisibilityOverrides = visibilityOverrides; @@ -54,6 +55,7 @@ public class NotificationRankingUpdate implements Parcelable { mSnoozeCriteria = snoozeCriteria; mShowBadge = showBadge; mUserSentiment = userSentiment; + mHidden = hidden; } public NotificationRankingUpdate(Parcel in) { @@ -70,6 +72,7 @@ public class NotificationRankingUpdate implements Parcelable { mSnoozeCriteria = in.readBundle(); mShowBadge = in.readBundle(); mUserSentiment = in.readBundle(); + mHidden = in.readBundle(); } @Override @@ -91,6 +94,7 @@ public class NotificationRankingUpdate implements Parcelable { out.writeBundle(mSnoozeCriteria); out.writeBundle(mShowBadge); out.writeBundle(mUserSentiment); + out.writeBundle(mHidden); } public static final Parcelable.Creator CREATOR @@ -151,4 +155,8 @@ public class NotificationRankingUpdate implements Parcelable { public Bundle getUserSentiment() { return mUserSentiment; } + + public Bundle getHidden() { + return mHidden; + } } diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 740a387e078d78c954f12dacad7d0c006142c890..3830b7ac1aee0157bb5a671bd63da662c0afe245 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -97,7 +97,7 @@ public class ZenModeConfig implements Parcelable { private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS = Policy.getAllSuppressedVisualEffects(); - public static final int XML_VERSION = 5; + public static final int XML_VERSION = 6; public static final String ZEN_TAG = "zen"; private static final String ZEN_ATT_VERSION = "version"; private static final String ZEN_ATT_USER = "user"; @@ -516,11 +516,17 @@ public class ZenModeConfig implements Parcelable { throw new IllegalStateException("Failed to reach END_DOCUMENT"); } - public void writeXml(XmlSerializer out) throws IOException { + /** + * Writes XML of current ZenModeConfig + * @param out serializer + * @param version uses XML_VERSION if version is null + * @throws IOException + */ + public void writeXml(XmlSerializer out, Integer version) throws IOException { out.startTag(null, ZEN_TAG); - out.attribute(null, ZEN_ATT_VERSION, Integer.toString(XML_VERSION)); + out.attribute(null, ZEN_ATT_VERSION, version == null + ? Integer.toString(XML_VERSION) : Integer.toString(version)); out.attribute(null, ZEN_ATT_USER, Integer.toString(user)); - out.startTag(null, ALLOW_TAG); out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls)); out.attribute(null, ALLOW_ATT_REPEAT_CALLERS, Boolean.toString(allowRepeatCallers)); diff --git a/core/java/android/service/textclassifier/ITextClassifierService.aidl b/core/java/android/service/textclassifier/ITextClassifierService.aidl index d2ffe345ae381d89dfdf8cb19eb73fed1de7ff1a..25e9d454efb58399502f26179af83b3bdc98571e 100644 --- a/core/java/android/service/textclassifier/ITextClassifierService.aidl +++ b/core/java/android/service/textclassifier/ITextClassifierService.aidl @@ -19,13 +19,14 @@ package android.service.textclassifier; import android.service.textclassifier.ITextClassificationCallback; import android.service.textclassifier.ITextLinksCallback; import android.service.textclassifier.ITextSelectionCallback; +import android.view.textclassifier.SelectionEvent; import android.view.textclassifier.TextClassification; import android.view.textclassifier.TextLinks; import android.view.textclassifier.TextSelection; /** * TextClassifierService binder interface. - * See TextClassifier for interface documentation. + * See TextClassifier (and TextClassifier.Logger) for interface documentation. * {@hide} */ oneway interface ITextClassifierService { @@ -44,4 +45,6 @@ oneway interface ITextClassifierService { in CharSequence text, in TextLinks.Options options, in ITextLinksCallback c); + + void onSelectionEvent(in SelectionEvent event); } diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java index 2c8c4ecaa6104acb2afb2d4af452c52ed4807d84..88e29b0d3d1170d04ea0e006471d02926c41d9a7 100644 --- a/core/java/android/service/textclassifier/TextClassifierService.java +++ b/core/java/android/service/textclassifier/TextClassifierService.java @@ -33,7 +33,9 @@ import android.os.IBinder; import android.os.RemoteException; import android.text.TextUtils; import android.util.Slog; +import android.view.textclassifier.SelectionEvent; import android.view.textclassifier.TextClassification; +import android.view.textclassifier.TextClassificationManager; import android.view.textclassifier.TextClassifier; import android.view.textclassifier.TextLinks; import android.view.textclassifier.TextSelection; @@ -47,7 +49,7 @@ import android.view.textclassifier.TextSelection; * {@link android.view.textclassifier.TextClassifierImpl} is loaded in the calling app's process. * *

    See: {@link TextClassifier}. - * See: {@link android.view.textclassifier.TextClassificationManager}. + * See: {@link TextClassificationManager}. * *

    Include the following in the manifest: * @@ -170,6 +172,12 @@ public abstract class TextClassifierService extends Service { } }); } + + /** {@inheritDoc} */ + @Override + public void onSelectionEvent(SelectionEvent event) throws RemoteException { + TextClassifierService.this.onSelectionEvent(event); + } }; @Nullable @@ -236,6 +244,27 @@ public abstract class TextClassifierService extends Service { @NonNull CancellationSignal cancellationSignal, @NonNull Callback callback); + /** + * Writes the selection event. + * This is called when a selection event occurs. e.g. user changed selection; or smart selection + * happened. + * + *

    The default implementation ignores the event. + */ + public void onSelectionEvent(@NonNull SelectionEvent event) {} + + /** + * Returns a TextClassifier that runs in this service's process. + * If the local TextClassifier is disabled, this returns {@link TextClassifier#NO_OP}. + */ + public final TextClassifier getLocalTextClassifier() { + final TextClassificationManager tcm = getSystemService(TextClassificationManager.class); + if (tcm != null) { + return tcm.getTextClassifier(TextClassifier.LOCAL); + } + return TextClassifier.NO_OP; + } + /** * Callbacks for TextClassifierService results. * diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java index 40e84b9604e7bafbaf48d9c641f9601f375926a7..61277e285b8620b647acfc85312d15f6edef3c36 100644 --- a/core/java/android/service/trust/TrustAgentService.java +++ b/core/java/android/service/trust/TrustAgentService.java @@ -545,7 +545,7 @@ public class TrustAgentService extends Service { */ public final void unlockUserWithToken(long handle, byte[] token, UserHandle user) { UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); - if (um.isUserUnlocked()) { + if (um.isUserUnlocked(user)) { Slog.i(TAG, "User already unlocked"); return; } diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java index aafcf44a73fcf00f9f9195f67830467670bb41f7..980f47043269e3f2280c67479f63a5d294ad28b8 100644 --- a/core/java/android/text/MeasuredParagraph.java +++ b/core/java/android/text/MeasuredParagraph.java @@ -675,7 +675,7 @@ public class MeasuredParagraph { /** * This only works if the MeasuredParagraph is computed with buildForStaticLayout. */ - @IntRange(from = 0) int getMemoryUsage() { + public @IntRange(from = 0) int getMemoryUsage() { return nGetMemoryUsage(mNativePtr); } diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java index b74019373f572b7feffd5823c5ae58dbfba08a23..9458184ee888ad8c9f308b0e6f4baf635ae2e88b 100644 --- a/core/java/android/text/PrecomputedText.java +++ b/core/java/android/text/PrecomputedText.java @@ -19,7 +19,6 @@ package android.text; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.util.IntArray; import com.android.internal.util.Preconditions; @@ -267,6 +266,22 @@ public class PrecomputedText implements Spanned { } }; + /** @hide */ + public static class ParagraphInfo { + public final @IntRange(from = 0) int paragraphEnd; + public final @NonNull MeasuredParagraph measured; + + /** + * @param paraEnd the end offset of this paragraph + * @param measured a measured paragraph + */ + public ParagraphInfo(@IntRange(from = 0) int paraEnd, @NonNull MeasuredParagraph measured) { + this.paragraphEnd = paraEnd; + this.measured = measured; + } + }; + + // The original text. private final @NonNull SpannedString mText; @@ -278,11 +293,8 @@ public class PrecomputedText implements Spanned { private final @NonNull Params mParams; - // The measured paragraph texts. - private final @NonNull MeasuredParagraph[] mMeasuredParagraphs; - - // The sorted paragraph end offsets. - private final @NonNull int[] mParagraphBreakPoints; + // The list of measured paragraph info. + private final @NonNull ParagraphInfo[] mParagraphInfo; /** * Create a new {@link PrecomputedText} which will pre-compute text measurement and glyph @@ -293,28 +305,25 @@ public class PrecomputedText implements Spanned { *

    * * @param text the text to be measured - * @param param parameters that define how text will be precomputed + * @param params parameters that define how text will be precomputed * @return A {@link PrecomputedText} */ - public static PrecomputedText create(@NonNull CharSequence text, @NonNull Params param) { - return createInternal(text, param, 0, text.length(), true /* compute full Layout */); + public static PrecomputedText create(@NonNull CharSequence text, @NonNull Params params) { + ParagraphInfo[] paraInfo = createMeasuredParagraphs( + text, params, 0, text.length(), true /* computeLayout */); + return new PrecomputedText(text, 0, text.length(), params, paraInfo); } /** @hide */ - public static PrecomputedText createWidthOnly(@NonNull CharSequence text, @NonNull Params param, - @IntRange(from = 0) int start, @IntRange(from = 0) int end) { - return createInternal(text, param, start, end, false /* compute width only */); - } - - private static PrecomputedText createInternal(@NonNull CharSequence text, @NonNull Params param, + public static ParagraphInfo[] createMeasuredParagraphs( + @NonNull CharSequence text, @NonNull Params params, @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean computeLayout) { - Preconditions.checkNotNull(text); - Preconditions.checkNotNull(param); - final boolean needHyphenation = param.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE - && param.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE; + ArrayList result = new ArrayList<>(); - final IntArray paragraphEnds = new IntArray(); - final ArrayList measuredTexts = new ArrayList<>(); + Preconditions.checkNotNull(text); + Preconditions.checkNotNull(params); + final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE + && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE; int paraEnd = 0; for (int paraStart = start; paraStart < end; paraStart = paraEnd) { @@ -327,27 +336,22 @@ public class PrecomputedText implements Spanned { paraEnd++; // Includes LINE_FEED(U+000A) to the prev paragraph. } - paragraphEnds.add(paraEnd); - measuredTexts.add(MeasuredParagraph.buildForStaticLayout( - param.getTextPaint(), text, paraStart, paraEnd, param.getTextDirection(), - needHyphenation, computeLayout, null /* no recycle */)); + result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout( + params.getTextPaint(), text, paraStart, paraEnd, params.getTextDirection(), + needHyphenation, computeLayout, null /* no recycle */))); } - - return new PrecomputedText(text, start, end, param, - measuredTexts.toArray(new MeasuredParagraph[measuredTexts.size()]), - paragraphEnds.toArray()); + return result.toArray(new ParagraphInfo[result.size()]); } // Use PrecomputedText.create instead. private PrecomputedText(@NonNull CharSequence text, @IntRange(from = 0) int start, - @IntRange(from = 0) int end, @NonNull Params param, - @NonNull MeasuredParagraph[] measuredTexts, @NonNull int[] paragraphBreakPoints) { + @IntRange(from = 0) int end, @NonNull Params params, + @NonNull ParagraphInfo[] paraInfo) { mText = new SpannedString(text); mStart = start; mEnd = end; - mParams = param; - mMeasuredParagraphs = measuredTexts; - mParagraphBreakPoints = paragraphBreakPoints; + mParams = params; + mParagraphInfo = paraInfo; } /** @@ -384,7 +388,7 @@ public class PrecomputedText implements Spanned { * Returns the count of paragraphs. */ public @IntRange(from = 0) int getParagraphCount() { - return mParagraphBreakPoints.length; + return mParagraphInfo.length; } /** @@ -392,7 +396,7 @@ public class PrecomputedText implements Spanned { */ public @IntRange(from = 0) int getParagraphStart(@IntRange(from = 0) int paraIndex) { Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex"); - return paraIndex == 0 ? mStart : mParagraphBreakPoints[paraIndex - 1]; + return paraIndex == 0 ? mStart : getParagraphEnd(paraIndex - 1); } /** @@ -400,12 +404,17 @@ public class PrecomputedText implements Spanned { */ public @IntRange(from = 0) int getParagraphEnd(@IntRange(from = 0) int paraIndex) { Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex"); - return mParagraphBreakPoints[paraIndex]; + return mParagraphInfo[paraIndex].paragraphEnd; } /** @hide */ public @NonNull MeasuredParagraph getMeasuredParagraph(@IntRange(from = 0) int paraIndex) { - return mMeasuredParagraphs[paraIndex]; + return mParagraphInfo[paraIndex].measured; + } + + /** @hide */ + public @NonNull ParagraphInfo[] getParagraphInfo() { + return mParagraphInfo; } /** @@ -425,13 +434,13 @@ public class PrecomputedText implements Spanned { public int findParaIndex(@IntRange(from = 0) int pos) { // TODO: Maybe good to remove paragraph concept from PrecomputedText and add substring // layout support to StaticLayout. - for (int i = 0; i < mParagraphBreakPoints.length; ++i) { - if (pos < mParagraphBreakPoints[i]) { + for (int i = 0; i < mParagraphInfo.length; ++i) { + if (pos < mParagraphInfo[i].paragraphEnd) { return i; } } throw new IndexOutOfBoundsException( - "pos must be less than " + mParagraphBreakPoints[mParagraphBreakPoints.length - 1] + "pos must be less than " + mParagraphInfo[mParagraphInfo.length - 1].paragraphEnd + ", gave " + pos); } diff --git a/core/java/android/text/SpannableString.java b/core/java/android/text/SpannableString.java index 56d0946babf23b306e2959e6e6818d7603249d19..afb5df809bc032633248c57a3a7673a8574748a1 100644 --- a/core/java/android/text/SpannableString.java +++ b/core/java/android/text/SpannableString.java @@ -16,7 +16,6 @@ package android.text; - /** * This is the class for text whose content is immutable but to which * markup objects can be attached and detached. @@ -26,12 +25,27 @@ public class SpannableString extends SpannableStringInternal implements CharSequence, GetChars, Spannable { + /** + * @param source source object to copy from + * @param ignoreNoCopySpan whether to copy NoCopySpans in the {@code source} + * @hide + */ + public SpannableString(CharSequence source, boolean ignoreNoCopySpan) { + super(source, 0, source.length(), ignoreNoCopySpan); + } + + /** + * For the backward compatibility reasons, this constructor copies all spans including {@link + * android.text.NoCopySpan}. + * @param source source text + */ public SpannableString(CharSequence source) { - super(source, 0, source.length()); + this(source, false /* ignoreNoCopySpan */); // preserve existing NoCopySpan behavior } private SpannableString(CharSequence source, int start, int end) { - super(source, start, end); + // preserve existing NoCopySpan behavior + super(source, start, end, false /* ignoreNoCopySpan */); } public static SpannableString valueOf(CharSequence source) { diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java index 366ec145ffc44bfe57a728d43bada5a538d5b0f4..5dd1a52b4a7a07b3b87f8a2136713ba64e4d407e 100644 --- a/core/java/android/text/SpannableStringInternal.java +++ b/core/java/android/text/SpannableStringInternal.java @@ -26,7 +26,7 @@ import java.lang.reflect.Array; /* package */ abstract class SpannableStringInternal { /* package */ SpannableStringInternal(CharSequence source, - int start, int end) { + int start, int end, boolean ignoreNoCopySpan) { if (start == 0 && end == source.length()) mText = source.toString(); else @@ -38,24 +38,37 @@ import java.lang.reflect.Array; if (source instanceof Spanned) { if (source instanceof SpannableStringInternal) { - copySpans((SpannableStringInternal) source, start, end); + copySpans((SpannableStringInternal) source, start, end, ignoreNoCopySpan); } else { - copySpans((Spanned) source, start, end); + copySpans((Spanned) source, start, end, ignoreNoCopySpan); } } } + /** + * This unused method is left since this is listed in hidden api list. + * + * Due to backward compatibility reasons, we copy even NoCopySpan by default + */ + /* package */ SpannableStringInternal(CharSequence source, int start, int end) { + this(source, start, end, false /* ignoreNoCopySpan */); + } + /** * Copies another {@link Spanned} object's spans between [start, end] into this object. * * @param src Source object to copy from. * @param start Start index in the source object. * @param end End index in the source object. + * @param ignoreNoCopySpan whether to copy NoCopySpans in the {@code source} */ - private final void copySpans(Spanned src, int start, int end) { + private void copySpans(Spanned src, int start, int end, boolean ignoreNoCopySpan) { Object[] spans = src.getSpans(start, end, Object.class); for (int i = 0; i < spans.length; i++) { + if (ignoreNoCopySpan && spans[i] instanceof NoCopySpan) { + continue; + } int st = src.getSpanStart(spans[i]); int en = src.getSpanEnd(spans[i]); int fl = src.getSpanFlags(spans[i]); @@ -76,35 +89,48 @@ import java.lang.reflect.Array; * @param src Source object to copy from. * @param start Start index in the source object. * @param end End index in the source object. + * @param ignoreNoCopySpan copy NoCopySpan for backward compatible reasons. */ - private final void copySpans(SpannableStringInternal src, int start, int end) { - if (start == 0 && end == src.length()) { + private void copySpans(SpannableStringInternal src, int start, int end, + boolean ignoreNoCopySpan) { + int count = 0; + final int[] srcData = src.mSpanData; + final Object[] srcSpans = src.mSpans; + final int limit = src.mSpanCount; + boolean hasNoCopySpan = false; + + for (int i = 0; i < limit; i++) { + int spanStart = srcData[i * COLUMNS + START]; + int spanEnd = srcData[i * COLUMNS + END]; + if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue; + if (srcSpans[i] instanceof NoCopySpan) { + hasNoCopySpan = true; + if (ignoreNoCopySpan) { + continue; + } + } + count++; + } + + if (count == 0) return; + + if (!hasNoCopySpan && start == 0 && end == src.length()) { mSpans = ArrayUtils.newUnpaddedObjectArray(src.mSpans.length); mSpanData = new int[src.mSpanData.length]; mSpanCount = src.mSpanCount; System.arraycopy(src.mSpans, 0, mSpans, 0, src.mSpans.length); System.arraycopy(src.mSpanData, 0, mSpanData, 0, mSpanData.length); } else { - int count = 0; - int[] srcData = src.mSpanData; - int limit = src.mSpanCount; - for (int i = 0; i < limit; i++) { - int spanStart = srcData[i * COLUMNS + START]; - int spanEnd = srcData[i * COLUMNS + END]; - if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue; - count++; - } - - if (count == 0) return; - - Object[] srcSpans = src.mSpans; mSpanCount = count; mSpans = ArrayUtils.newUnpaddedObjectArray(mSpanCount); mSpanData = new int[mSpans.length * COLUMNS]; for (int i = 0, j = 0; i < limit; i++) { int spanStart = srcData[i * COLUMNS + START]; int spanEnd = srcData[i * COLUMNS + END]; - if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue; + if (isOutOfCopyRange(start, end, spanStart, spanEnd) + || (ignoreNoCopySpan && srcSpans[i] instanceof NoCopySpan)) { + continue; + } if (spanStart < start) spanStart = start; if (spanEnd > end) spanEnd = end; @@ -494,6 +520,21 @@ import java.lang.reflect.Array; return hash; } + /** + * Following two unused methods are left since these are listed in hidden api list. + * + * Due to backward compatibility reasons, we copy even NoCopySpan by default + */ + private void copySpans(Spanned src, int start, int end) { + copySpans(src, start, end, false); + } + + private void copySpans(SpannableStringInternal src, int start, int end) { + copySpans(src, start, end, false); + } + + + private String mText; private Object[] mSpans; private int[] mSpanData; diff --git a/core/java/android/text/SpannedString.java b/core/java/android/text/SpannedString.java index afed221f4152f78a62b9d02730d63ef6bbf4010c..acee3c5f1a41a02b39edc7fa274c3eee4e16a6be 100644 --- a/core/java/android/text/SpannedString.java +++ b/core/java/android/text/SpannedString.java @@ -26,12 +26,27 @@ public final class SpannedString extends SpannableStringInternal implements CharSequence, GetChars, Spanned { + /** + * @param source source object to copy from + * @param ignoreNoCopySpan whether to copy NoCopySpans in the {@code source} + * @hide + */ + public SpannedString(CharSequence source, boolean ignoreNoCopySpan) { + super(source, 0, source.length(), ignoreNoCopySpan); + } + + /** + * For the backward compatibility reasons, this constructor copies all spans including {@link + * android.text.NoCopySpan}. + * @param source source text + */ public SpannedString(CharSequence source) { - super(source, 0, source.length()); + this(source, false /* ignoreNoCopySpan */); // preserve existing NoCopySpan behavior } private SpannedString(CharSequence source, int start, int end) { - super(source, start, end); + // preserve existing NoCopySpan behavior + super(source, start, end, false /* ignoreNoCopySpan */); } public CharSequence subSequence(int start, int end) { diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 299bde239fcfe4c42e7dbd67645c1b90d907eb87..0899074174a2c535ab6b973a616dffb545080651 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -651,31 +651,29 @@ public class StaticLayout extends Layout { b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE, indents, mLeftPaddings, mRightPaddings); - PrecomputedText measured = null; - final Spanned spanned; + PrecomputedText.ParagraphInfo[] paragraphInfo = null; + final Spanned spanned = (source instanceof Spanned) ? (Spanned) source : null; if (source instanceof PrecomputedText) { - measured = (PrecomputedText) source; - if (!measured.canUseMeasuredResult(bufStart, bufEnd, textDir, paint, b.mBreakStrategy, - b.mHyphenationFrequency)) { + PrecomputedText precomputed = (PrecomputedText) source; + if (precomputed.canUseMeasuredResult(bufStart, bufEnd, textDir, paint, + b.mBreakStrategy, b.mHyphenationFrequency)) { // Some parameters are different from the ones when measured text is created. - measured = null; + paragraphInfo = precomputed.getParagraphInfo(); } } - if (measured == null) { + if (paragraphInfo == null) { final PrecomputedText.Params param = new PrecomputedText.Params(paint, textDir, b.mBreakStrategy, b.mHyphenationFrequency); - measured = PrecomputedText.createWidthOnly(source, param, bufStart, bufEnd); - spanned = (source instanceof Spanned) ? (Spanned) source : null; - } else { - final CharSequence original = measured.getText(); - spanned = (original instanceof Spanned) ? (Spanned) original : null; + paragraphInfo = PrecomputedText.createMeasuredParagraphs(source, param, bufStart, + bufEnd, false /* computeLayout */); } try { - for (int paraIndex = 0; paraIndex < measured.getParagraphCount(); paraIndex++) { - final int paraStart = measured.getParagraphStart(paraIndex); - final int paraEnd = measured.getParagraphEnd(paraIndex); + for (int paraIndex = 0; paraIndex < paragraphInfo.length; paraIndex++) { + final int paraStart = paraIndex == 0 + ? bufStart : paragraphInfo[paraIndex - 1].paragraphEnd; + final int paraEnd = paragraphInfo[paraIndex].paragraphEnd; int firstWidthLineCount = 1; int firstWidth = outerWidth; @@ -741,7 +739,7 @@ public class StaticLayout extends Layout { } } - final MeasuredParagraph measuredPara = measured.getMeasuredParagraph(paraIndex); + final MeasuredParagraph measuredPara = paragraphInfo[paraIndex].measured; final char[] chs = measuredPara.getChars(); final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray(); final int[] fmCache = measuredPara.getFontMetrics().getRawArray(); diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java index c44f42b19ced8e6e9bd8522932ae29c9bf5450df..46e31693193515fe108d43c4111fbc67e8b0fda9 100644 --- a/core/java/android/util/DebugUtils.java +++ b/core/java/android/util/DebugUtils.java @@ -219,7 +219,7 @@ public class DebugUtils { && field.getType().equals(int.class) && field.getName().startsWith(prefix)) { try { if (value == field.getInt(null)) { - return field.getName().substring(prefix.length()); + return constNameWithoutPrefix(prefix, field); } } catch (IllegalAccessException ignored) { } @@ -236,6 +236,7 @@ public class DebugUtils { */ public static String flagsToString(Class clazz, String prefix, int flags) { final StringBuilder res = new StringBuilder(); + boolean flagsWasZero = flags == 0; for (Field field : clazz.getDeclaredFields()) { final int modifiers = field.getModifiers(); @@ -243,9 +244,12 @@ public class DebugUtils { && field.getType().equals(int.class) && field.getName().startsWith(prefix)) { try { final int value = field.getInt(null); + if (value == 0 && flagsWasZero) { + return constNameWithoutPrefix(prefix, field); + } if ((flags & value) != 0) { flags &= ~value; - res.append(field.getName().substring(prefix.length())).append('|'); + res.append(constNameWithoutPrefix(prefix, field)).append('|'); } } catch (IllegalAccessException ignored) { } @@ -258,4 +262,8 @@ public class DebugUtils { } return res.toString(); } + + private static String constNameWithoutPrefix(String prefix, Field field) { + return field.getName().substring(prefix.length()); + } } diff --git a/core/java/android/util/KeyValueSettingObserver.java b/core/java/android/util/KeyValueSettingObserver.java new file mode 100644 index 0000000000000000000000000000000000000000..9fca8b2cfab2b3a43d59e1a0ae90b1a1055e161f --- /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. + * + *

    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()}. + * + *

    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/util/StatsLog.java b/core/java/android/util/StatsLog.java index 3350f3e164bcfec842d8068bf307c309ed6ff3e6..e8b4197259ce09db4e26092c3519c82cad4dfb59 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -16,10 +16,11 @@ package android.util; +import android.os.Process; + /** * StatsLog provides an API for developers to send events to statsd. The events can be used to - * define custom metrics inside statsd. We will rate-limit how often the calls can be made inside - * statsd. + * define custom metrics inside statsd. */ public final class StatsLog extends StatsLogInternal { private static final String TAG = "StatsManager"; @@ -34,7 +35,8 @@ public final class StatsLog extends StatsLogInternal { */ public static boolean logStart(int label) { if (label >= 0 && label < 16) { - StatsLog.write(APP_BREADCRUMB_REPORTED, label, APP_BREADCRUMB_REPORTED__STATE__START); + StatsLog.write(APP_BREADCRUMB_REPORTED, Process.myUid(), + label, APP_BREADCRUMB_REPORTED__STATE__START); return true; } return false; @@ -48,7 +50,8 @@ public final class StatsLog extends StatsLogInternal { */ public static boolean logStop(int label) { if (label >= 0 && label < 16) { - StatsLog.write(APP_BREADCRUMB_REPORTED, label, APP_BREADCRUMB_REPORTED__STATE__STOP); + StatsLog.write(APP_BREADCRUMB_REPORTED, Process.myUid(), + label, APP_BREADCRUMB_REPORTED__STATE__STOP); return true; } return false; @@ -62,7 +65,7 @@ public final class StatsLog extends StatsLogInternal { */ public static boolean logEvent(int label) { if (label >= 0 && label < 16) { - StatsLog.write(APP_BREADCRUMB_REPORTED, label, + StatsLog.write(APP_BREADCRUMB_REPORTED, Process.myUid(), label, APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED); return true; } diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java index bb16afddcd63ec81f51fa462ac2b3444eea666b4..66a9c6c01ca40117389bfeeaa488b6b6e9cbc20e 100644 --- a/core/java/android/view/DisplayCutout.java +++ b/core/java/android/view/DisplayCutout.java @@ -18,10 +18,6 @@ package android.view; import static android.view.DisplayCutoutProto.BOUNDS; import static android.view.DisplayCutoutProto.INSETS; -import static android.view.Surface.ROTATION_0; -import static android.view.Surface.ROTATION_180; -import static android.view.Surface.ROTATION_270; -import static android.view.Surface.ROTATION_90; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; @@ -36,24 +32,26 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; import android.util.PathParser; -import android.util.Size; import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import java.util.Objects; +import java.util.ArrayList; +import java.util.List; /** - * Represents a part of the display that is not functional for displaying content. + * Represents the area of the display that is not functional for displaying content. * *

    {@code DisplayCutout} is immutable. */ public final class DisplayCutout { private static final String TAG = "DisplayCutout"; + private static final String BOTTOM_MARKER = "@bottom"; private static final String DP_MARKER = "@dp"; + private static final String RIGHT_MARKER = "@right"; /** * Category for overlays that allow emulating a display cutout on devices that don't have @@ -74,7 +72,7 @@ public final class DisplayCutout { * @hide */ public static final DisplayCutout NO_CUTOUT = new DisplayCutout(ZERO_RECT, EMPTY_REGION, - new Size(0, 0)); + false /* copyArguments */); private static final Object CACHE_LOCK = new Object(); @@ -89,38 +87,38 @@ public final class DisplayCutout { private final Rect mSafeInsets; private final Region mBounds; - private final Size mFrameSize; // TODO: move frameSize, calculateRelativeTo, etc. into WM. /** * Creates a DisplayCutout instance. * * @param safeInsets the insets from each edge which avoid the display cutout as returned by * {@link #getSafeInsetTop()} etc. - * @param bounds the bounds of the display cutout as returned by {@link #getBounds()}. + * @param boundingRects the bounding rects of the display cutouts as returned by + * {@link #getBoundingRects()} ()}. */ // TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE) - public DisplayCutout(Rect safeInsets, Region bounds) { + public DisplayCutout(Rect safeInsets, List boundingRects) { this(safeInsets != null ? new Rect(safeInsets) : ZERO_RECT, - bounds != null ? Region.obtain(bounds) : Region.obtain(), - null /* frameSize */); + boundingRectsToRegion(boundingRects), + true /* copyArguments */); } /** * Creates a DisplayCutout instance. * - * NOTE: the Rects passed into this instance are not copied and MUST remain unchanged. - * - * @hide + * @param copyArguments if true, create a copy of the arguments. If false, the passed arguments + * are not copied and MUST remain unchanged forever. */ - @VisibleForTesting - public DisplayCutout(Rect safeInsets, Region bounds, Size frameSize) { - mSafeInsets = safeInsets != null ? safeInsets : ZERO_RECT; - mBounds = bounds != null ? bounds : Region.obtain(); - mFrameSize = frameSize; + private DisplayCutout(Rect safeInsets, Region bounds, boolean copyArguments) { + mSafeInsets = safeInsets == null ? ZERO_RECT : + (copyArguments ? new Rect(safeInsets) : safeInsets); + mBounds = bounds == null ? Region.obtain() : + (copyArguments ? Region.obtain(bounds) : bounds); } /** - * Returns true if there is no cutout or it is outside of the content view. + * Returns true if the safe insets are empty (and therefore the current view does not + * overlap with the cutout or cutout area). * * @hide */ @@ -128,6 +126,15 @@ public final class DisplayCutout { return mSafeInsets.equals(ZERO_RECT); } + /** + * Returns true if there is no cutout, i.e. the bounds are empty. + * + * @hide + */ + public boolean isBoundsEmpty() { + return mBounds.isEmpty(); + } + /** Returns the inset from the top which avoids the display cutout in pixels. */ public int getSafeInsetTop() { return mSafeInsets.top; @@ -161,23 +168,60 @@ public final class DisplayCutout { /** * Returns the bounding region of the cutout. * + *

    + * Note: There may be more than one cutout, in which case the returned + * {@code Region} will be non-contiguous and its bounding rect will be meaningless without + * intersecting it first. + * + * Example: + *

    +     *     // Getting the bounding rectangle of the top display cutout
    +     *     Region bounds = displayCutout.getBounds();
    +     *     bounds.op(0, 0, Integer.MAX_VALUE, displayCutout.getSafeInsetTop(), Region.Op.INTERSECT);
    +     *     Rect topDisplayCutout = bounds.getBoundingRect();
    +     * 
    + * * @return the bounding region of the cutout. Coordinates are relative * to the top-left corner of the content view and in pixel units. + * @hide */ public Region getBounds() { return Region.obtain(mBounds); } /** - * Returns the bounding rect of the cutout. + * Returns a list of {@code Rect}s, each of which is the bounding rectangle for a non-functional + * area on the display. * - * @return the bounding rect of the cutout. Coordinates are relative - * to the top-left corner of the content view. - * @hide + * There will be at most one non-functional area per short edge of the device, and none on + * the long edges. + * + * @return a list of bounding {@code Rect}s, one for each display cutout area. */ - public Rect getBoundingRect() { - // TODO(roosa): Inline. - return mBounds.getBounds(); + public List getBoundingRects() { + List result = new ArrayList<>(); + Region bounds = Region.obtain(); + // top + bounds.set(mBounds); + bounds.op(0, 0, Integer.MAX_VALUE, getSafeInsetTop(), Region.Op.INTERSECT); + if (!bounds.isEmpty()) { + result.add(bounds.getBounds()); + } + // left + bounds.set(mBounds); + bounds.op(0, 0, getSafeInsetLeft(), Integer.MAX_VALUE, Region.Op.INTERSECT); + if (!bounds.isEmpty()) { + result.add(bounds.getBounds()); + } + // right & bottom + bounds.set(mBounds); + bounds.op(getSafeInsetLeft() + 1, getSafeInsetTop() + 1, + Integer.MAX_VALUE, Integer.MAX_VALUE, Region.Op.INTERSECT); + if (!bounds.isEmpty()) { + result.add(bounds.getBounds()); + } + bounds.recycle(); + return result; } @Override @@ -195,8 +239,7 @@ public final class DisplayCutout { if (o instanceof DisplayCutout) { DisplayCutout c = (DisplayCutout) o; return mSafeInsets.equals(c.mSafeInsets) - && mBounds.equals(c.mBounds) - && Objects.equals(mFrameSize, c.mFrameSize); + && mBounds.equals(c.mBounds); } return false; } @@ -204,7 +247,7 @@ public final class DisplayCutout { @Override public String toString() { return "DisplayCutout{insets=" + mSafeInsets - + " boundingRect=" + getBoundingRect() + + " boundingRect=" + mBounds.getBounds() + "}"; } @@ -249,88 +292,19 @@ public final class DisplayCutout { } bounds.translate(-insetLeft, -insetTop); - Size frame = mFrameSize == null ? null : new Size( - mFrameSize.getWidth() - insetLeft - insetRight, - mFrameSize.getHeight() - insetTop - insetBottom); - - return new DisplayCutout(safeInsets, bounds, frame); + return new DisplayCutout(safeInsets, bounds, false /* copyArguments */); } /** - * Recalculates the cutout relative to the given reference frame. + * Returns a copy of this instance with the safe insets replaced with the parameter. * - * The safe insets must already have been computed, e.g. with {@link #computeSafeInsets}. + * @param safeInsets the new safe insets in pixels + * @return a copy of this instance with the safe insets replaced with the argument. * - * @return a copy of this instance with the safe insets recalculated * @hide */ - public DisplayCutout calculateRelativeTo(Rect frame) { - return inset(frame.left, frame.top, - mFrameSize.getWidth() - frame.right, mFrameSize.getHeight() - frame.bottom); - } - - /** - * Calculates the safe insets relative to the given display size. - * - * @return a copy of this instance with the safe insets calculated - * @hide - */ - public DisplayCutout computeSafeInsets(int width, int height) { - if (this == NO_CUTOUT || mBounds.isEmpty()) { - return NO_CUTOUT; - } - - return computeSafeInsets(new Size(width, height), mBounds); - } - - private static DisplayCutout computeSafeInsets(Size displaySize, Region bounds) { - Rect boundingRect = bounds.getBounds(); - Rect safeRect = new Rect(); - - int bestArea = 0; - int bestVariant = 0; - for (int variant = ROTATION_0; variant <= ROTATION_270; variant++) { - int area = calculateInsetVariantArea(displaySize, boundingRect, variant, safeRect); - if (bestArea < area) { - bestArea = area; - bestVariant = variant; - } - } - calculateInsetVariantArea(displaySize, boundingRect, bestVariant, safeRect); - if (safeRect.isEmpty()) { - // The entire displaySize overlaps with the cutout. - safeRect.set(0, displaySize.getHeight(), 0, 0); - } else { - // Convert safeRect to insets relative to displaySize. We're reusing the rect here to - // avoid an allocation. - safeRect.set( - Math.max(0, safeRect.left), - Math.max(0, safeRect.top), - Math.max(0, displaySize.getWidth() - safeRect.right), - Math.max(0, displaySize.getHeight() - safeRect.bottom)); - } - - return new DisplayCutout(safeRect, bounds, displaySize); - } - - private static int calculateInsetVariantArea(Size display, Rect boundingRect, int variant, - Rect outSafeRect) { - switch (variant) { - case ROTATION_0: - outSafeRect.set(0, 0, display.getWidth(), boundingRect.top); - break; - case ROTATION_90: - outSafeRect.set(0, 0, boundingRect.left, display.getHeight()); - break; - case ROTATION_180: - outSafeRect.set(0, boundingRect.bottom, display.getWidth(), display.getHeight()); - break; - case ROTATION_270: - outSafeRect.set(boundingRect.right, 0, display.getWidth(), display.getHeight()); - break; - } - - return outSafeRect.isEmpty() ? 0 : outSafeRect.width() * outSafeRect.height(); + public DisplayCutout replaceSafeInsets(Rect safeInsets) { + return new DisplayCutout(new Rect(safeInsets), mBounds, false /* copyArguments */); } private static int atLeastZero(int value) { @@ -369,7 +343,7 @@ public final class DisplayCutout { Region bounds = new Region(); bounds.setPath(path, clipRegion); clipRegion.recycle(); - return new DisplayCutout(ZERO_RECT, bounds, null /* frameSize */); + return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */); } /** @@ -377,9 +351,9 @@ public final class DisplayCutout { * * @hide */ - public static DisplayCutout fromResources(Resources res, int displayWidth) { + public static DisplayCutout fromResources(Resources res, int displayWidth, int displayHeight) { return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout), - displayWidth, res.getDisplayMetrics().density); + displayWidth, displayHeight, res.getDisplayMetrics().density); } /** @@ -388,7 +362,8 @@ public final class DisplayCutout { * @hide */ @VisibleForTesting(visibility = PRIVATE) - public static DisplayCutout fromSpec(String spec, int displayWidth, float density) { + public static DisplayCutout fromSpec(String spec, int displayWidth, int displayHeight, + float density) { if (TextUtils.isEmpty(spec)) { return null; } @@ -399,12 +374,26 @@ public final class DisplayCutout { } } spec = spec.trim(); + final float offsetX; + if (spec.endsWith(RIGHT_MARKER)) { + offsetX = displayWidth; + spec = spec.substring(0, spec.length() - RIGHT_MARKER.length()).trim(); + } else { + offsetX = displayWidth / 2f; + } final boolean inDp = spec.endsWith(DP_MARKER); if (inDp) { spec = spec.substring(0, spec.length() - DP_MARKER.length()); } - Path p; + String bottomSpec = null; + if (spec.contains(BOTTOM_MARKER)) { + String[] splits = spec.split(BOTTOM_MARKER, 2); + spec = splits[0].trim(); + bottomSpec = splits[1].trim(); + } + + final Path p; try { p = PathParser.createPathFromPathData(spec); } catch (Throwable e) { @@ -416,9 +405,23 @@ public final class DisplayCutout { if (inDp) { m.postScale(density, density); } - m.postTranslate(displayWidth / 2f, 0); + m.postTranslate(offsetX, 0); p.transform(m); + if (bottomSpec != null) { + final Path bottomPath; + try { + bottomPath = PathParser.createPathFromPathData(bottomSpec); + } catch (Throwable e) { + Log.wtf(TAG, "Could not inflate bottom cutout: ", e); + return null; + } + // Keep top transform + m.postTranslate(0, displayHeight); + bottomPath.transform(m); + p.addPath(bottomPath); + } + final DisplayCutout result = fromBounds(p); synchronized (CACHE_LOCK) { sCachedSpec = spec; @@ -429,6 +432,16 @@ public final class DisplayCutout { return result; } + private static Region boundingRectsToRegion(List rects) { + Region result = Region.obtain(); + if (rects != null) { + for (Rect r : rects) { + result.op(r, Region.Op.UNION); + } + } + return result; + } + /** * Helper class for passing {@link DisplayCutout} through binder. * @@ -472,12 +485,6 @@ public final class DisplayCutout { out.writeInt(1); out.writeTypedObject(cutout.mSafeInsets, flags); out.writeTypedObject(cutout.mBounds, flags); - if (cutout.mFrameSize != null) { - out.writeInt(cutout.mFrameSize.getWidth()); - out.writeInt(cutout.mFrameSize.getHeight()); - } else { - out.writeInt(-1); - } } } @@ -520,10 +527,7 @@ public final class DisplayCutout { Rect safeInsets = in.readTypedObject(Rect.CREATOR); Region bounds = in.readTypedObject(Region.CREATOR); - int width = in.readInt(); - Size frameSize = width >= 0 ? new Size(width, in.readInt()) : null; - - return new DisplayCutout(safeInsets, bounds, frameSize); + return new DisplayCutout(safeInsets, bounds, false /* copyArguments */); } public DisplayCutout get() { diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl index 9382741a81ec8471e3b76a71f98352cd85b0ef59..2da353b1f0ee9b37b467db3419ad63fb3013adf5 100644 --- a/core/java/android/view/IPinnedStackListener.aidl +++ b/core/java/android/view/IPinnedStackListener.aidl @@ -47,16 +47,24 @@ oneway interface IPinnedStackListener { * the WM has changed in the mean time but the client has not received onMovementBoundsChanged). */ void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds, in Rect animatingBounds, - boolean fromImeAdjustement, int displayRotation); + boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation); /** * Called when window manager decides to adjust the pinned stack bounds because of the IME, or * when the listener is first registered to allow the listener to synchronized its state with * the controller. This call will always be followed by a onMovementBoundsChanged() call - * with fromImeAdjustement set to true. + * with fromImeAdjustement set to {@code true}. */ void onImeVisibilityChanged(boolean imeVisible, int imeHeight); + /** + * Called when window manager decides to adjust the pinned stack bounds because of the shelf, or + * when the listener is first registered to allow the listener to synchronized its state with + * the controller. This call will always be followed by a onMovementBoundsChanged() call + * with fromShelfAdjustment set to {@code true}. + */ + void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight); + /** * Called when window manager decides to adjust the minimized state, or when the listener * is first registered to allow the listener to synchronized its state with the controller. diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index 5607b1134e5b1e1bb9d360bade6a4ed5bd1198ea..89684ca46003ccef23bf40db9153752f542a3b21 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/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 77a74e260811e99ebab0e8bfd20bc179ef26c019..6486230f8e3a866482b12473bf50c6a0aa39b654 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -181,9 +181,10 @@ interface IWindowManager void setStrictModeVisualIndicatorPreference(String enabled); /** - * Set whether screen capture is disabled for all windows of a specific user + * Set whether screen capture is disabled for all windows of a specific user from + * the device policy cache. */ - void setScreenCaptureDisabled(int userId, boolean disabled); + void refreshScreenCaptureDisabled(int userId); // These can only be called with the SET_ORIENTATION permission. /** @@ -283,7 +284,12 @@ interface IWindowManager */ oneway void setPipVisibility(boolean visible); - /** + /** + * Called by System UI to notify of changes to the visibility and height of the shelf. + */ + void setShelfHeight(boolean visible, int shelfHeight); + + /** * Called by System UI to enable or disable haptic feedback on the navigation bar buttons. */ void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled); @@ -294,8 +300,8 @@ interface IWindowManager boolean hasNavigationBar(); /** - * Get the position of the nav bar - */ + * Get the position of the nav bar + */ int getNavBarPosition(); /** @@ -422,4 +428,14 @@ interface IWindowManager * on the next user activity. */ void requestUserActivityNotification(); + + /** + * Notify WindowManager that it should not override the info in DisplayManager for the specified + * display. This can disable letter- or pillar-boxing applied in DisplayManager when the metrics + * of the logical display reported from WindowManager do not correspond to the metrics of the + * physical display it is based on. + * + * @param displayId The id of the display. + */ + void dontOverrideDisplayInfo(int displayId); } diff --git a/core/java/android/view/RecordingCanvas.java b/core/java/android/view/RecordingCanvas.java index fc7d828de12ef008f1cb68e84b30270217892f4a..f7a41ffa67e50c5f78785a87f3fd088b6e0880c1 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 8def43512e513513b7af6cf56fc8473b5e44dd06..d2240e1f2775036a8381a4aa5ea3433b2e524136 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 mTransitionAnimationMap; + private final SparseArray 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 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 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 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 CREATOR + = new Creator() { + + @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 75cdd49fccab17b57fbab812c8e80b4a9d46ca2a..5b2cc81756c103e162f08c1e0ee46496703e1234 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 CREATOR = new Creator() { public RemoteAnimationTarget createFromParcel(Parcel in) { diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index b7524fb1a5220ff4a950dce6664604a8768b0e1d..7ff4f21dd26fec05724a09587a0718fc5cb4c1e3 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -566,7 +566,7 @@ public class SurfaceControl implements Parcelable { */ private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags, SurfaceControl parent, int windowType, int ownerUid) - throws OutOfResourcesException { + throws OutOfResourcesException, IllegalArgumentException { if (session == null) { throw new IllegalArgumentException("session must not be null"); } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 4a9da4a6672f0fb4d85ca9c412d5e844184841c4..f930f6e3f11babe93f9c9365644126c867fd5a5e 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -16,7 +16,6 @@ package android.view; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER; import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER; import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER; @@ -180,6 +179,8 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb private int mPendingReportDraws; + private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction(); + public SurfaceView(Context context) { this(context, null); } @@ -775,21 +776,34 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb }); } + /** + * A place to over-ride for applying child-surface transactions. + * These can be synchronized with the viewroot surface using deferTransaction. + * + * Called from RenderWorker while UI thread is paused. + * @hide + */ + protected void applyChildSurfaceTransaction_renderWorker(SurfaceControl.Transaction t, + Surface viewRootSurface, long nextViewRootFrameNumber) { + } + private void setParentSpaceRectangle(Rect position, long frameNumber) { ViewRootImpl viewRoot = getViewRootImpl(); - SurfaceControl.openTransaction(); - try { - if (frameNumber > 0) { - mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber); - } - mSurfaceControl.setPosition(position.left, position.top); - mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth, - 0.0f, 0.0f, - position.height() / (float) mSurfaceHeight); - } finally { - SurfaceControl.closeTransaction(); + if (frameNumber > 0) { + mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface, + frameNumber); } + mRtTransaction.setPosition(mSurfaceControl,position.left, position.top); + mRtTransaction.setMatrix(mSurfaceControl, + position.width() / (float) mSurfaceWidth, + 0.0f, 0.0f, + position.height() / (float) mSurfaceHeight); + + applyChildSurfaceTransaction_renderWorker(mRtTransaction, viewRoot.mSurface, + frameNumber); + + mRtTransaction.apply(); } private Rect mRTLastReportedPosition = new Rect(); @@ -877,31 +891,6 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb return callbacks; } - /** - * This method still exists only for compatibility reasons because some applications have relied - * on this method via reflection. See Issue 36345857 for details. - * - * @deprecated No platform code is using this method anymore. - * @hide - */ - @Deprecated - public void setWindowType(int type) { - if (getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) { - throw new UnsupportedOperationException( - "SurfaceView#setWindowType() has never been a public API."); - } - - if (type == TYPE_APPLICATION_PANEL) { - Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) " - + "just to make the SurfaceView to be placed on top of its window, you must " - + "call setZOrderOnTop(true) instead.", new Throwable()); - setZOrderOnTop(true); - return; - } - Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. " - + "type=" + type, new Throwable()); - } - private void runOnUiThread(Runnable runnable) { Handler handler = getHandler(); if (handler != null && handler.getLooper() != Looper.myLooper()) { diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 8d076f75ddbb63fba3dc790403206c6c6ba9c518..5eb7e9cb2efed0aed0ecca54f0efdd09fc4a0a07 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -20,13 +20,11 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.app.ActivityManager; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.AnimatedVectorDrawable; -import android.os.Build; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -936,6 +934,20 @@ public final class ThreadedRenderer { nSetHighContrastText(highContrastText); } + /** + * If set RenderThread will avoid doing any IPC using instead a fake vsync & DisplayInfo source + */ + public static void setIsolatedProcess(boolean isIsolated) { + nSetIsolatedProcess(isIsolated); + } + + /** + * If set extra graphics debugging abilities will be enabled such as dumping skp + */ + public static void setDebuggingEnabled(boolean enable) { + nSetDebuggingEnabled(enable); + } + @Override protected void finalize() throws Throwable { try { @@ -1071,10 +1083,6 @@ public final class ThreadedRenderer { initSched(renderProxy); if (mAppContext != null) { - final boolean appDebuggable = - (mAppContext.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) - != 0; - nSetDebuggingEnabled(appDebuggable || Build.IS_DEBUGGABLE); initGraphicsStats(); } } @@ -1204,4 +1212,5 @@ public final class ThreadedRenderer { // For temporary experimentation b/66945974 private static native void nHackySetRTAnimationsEnabled(boolean enabled); private static native void nSetDebuggingEnabled(boolean enabled); + private static native void nSetIsolatedProcess(boolean enabled); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index bf0e2ebf6debecbbdbf838302aa7d8995ec25e07..afff19b0be315a047178bdf065803a35b40cffb5 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; } } } @@ -8910,7 +8910,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (node != null) { return node.isVisibleToUser(); } + // if node is null, assume it's not visible anymore + } else { + Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); } + return false; } return true; } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 8e60a720f729ee6b00e06ee6f42123e6440ba05e..33fcf6a74aa17716a16d67b8b862b238d13f7c6f 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -4285,6 +4285,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager recreateChildDisplayList(child); } } + final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size(); + for (int i = 0; i < transientCount; ++i) { + View child = mTransientViews.get(i); + if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) { + recreateChildDisplayList(child); + } + } if (mOverlay != null) { View overlayView = mOverlay.getOverlayView(); recreateChildDisplayList(overlayView); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index c36ab5d1310aa268ccdebe548a061b7a5be8d75a..12369624da30f1767b02d890e4b3ade297c60aaf 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -29,6 +29,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; import android.Manifest; import android.animation.LayoutTransition; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ResourcesManager; @@ -4166,9 +4167,7 @@ public final class ViewRootImpl implements ViewParent, Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView); } KeyEvent event = (KeyEvent) msg.obj; - // send InputEvent to pre IME, set FLAG_FROM_AUTOFILL so the InputEvent - // wont be dropped as app window is not focus. - enqueueInputEvent(event, null, QueuedInputEvent.FLAG_FROM_AUTOFILL, true); + enqueueInputEvent(event, null, 0, true); } break; case MSG_CHECK_FOCUS: { InputMethodManager imm = InputMethodManager.peekInstance(); @@ -4461,7 +4460,7 @@ public final class ViewRootImpl implements ViewParent, return true; } else if ((!mAttachInfo.mHasWindowFocus && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) - && (q.mFlags & QueuedInputEvent.FLAG_FROM_AUTOFILL) == 0) || mStopped + && !isAutofillUiShowing()) || mStopped || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) || (mPausedForTransition && !isBack(q.mEvent))) { // This is a focus event and the window doesn't currently have input focus or @@ -4796,18 +4795,11 @@ public final class ViewRootImpl implements ViewParent, ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)); } - if (action == MotionEvent.ACTION_DOWN && mView instanceof ViewGroup) { + if (action == MotionEvent.ACTION_DOWN) { // Upon motion event within app window, close autofill ui. - ViewGroup decorView = (ViewGroup) mView; - if (decorView.getChildCount() > 0) { - // We cannot use decorView's Context for querying AutofillManager: DecorView's - // context is based on Application Context, it would allocate a different - // AutofillManager instance. - AutofillManager afm = (AutofillManager) decorView.getChildAt(0).getContext() - .getSystemService(Context.AUTOFILL_MANAGER_SERVICE); - if (afm != null) { - afm.requestHideFillUi(); - } + AutofillManager afm = getAutofillManager(); + if (afm != null) { + afm.requestHideFillUi(); } } @@ -6456,6 +6448,28 @@ public final class ViewRootImpl implements ViewParent, return mAudioManager; } + private @Nullable AutofillManager getAutofillManager() { + if (mView instanceof ViewGroup) { + ViewGroup decorView = (ViewGroup) mView; + if (decorView.getChildCount() > 0) { + // We cannot use decorView's Context for querying AutofillManager: DecorView's + // context is based on Application Context, it would allocate a different + // AutofillManager instance. + return decorView.getChildAt(0).getContext() + .getSystemService(AutofillManager.class); + } + } + return null; + } + + private boolean isAutofillUiShowing() { + AutofillManager afm = getAutofillManager(); + if (afm == null) { + return false; + } + return afm.isAutofillUiShowing(); + } + public AccessibilityInteractionController getAccessibilityInteractionController() { if (mView == null) { throw new IllegalStateException("getAccessibilityInteractionController" @@ -6861,7 +6875,6 @@ public final class ViewRootImpl implements ViewParent, public static final int FLAG_FINISHED_HANDLED = 1 << 3; public static final int FLAG_RESYNTHESIZED = 1 << 4; public static final int FLAG_UNHANDLED = 1 << 5; - public static final int FLAG_FROM_AUTOFILL = 1 << 6; public QueuedInputEvent mNext; diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 2354f255c30b4f974e1f277f69fbb601d047514d..69938cbe8bb6918371351d37282c26bf0da75a82 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -2241,18 +2241,20 @@ public interface WindowManager extends ViewManager { /** * The window is allowed to extend into the {@link DisplayCutout} area, only if the - * {@link DisplayCutout} is fully contained within the status bar. Otherwise, the window is + * {@link DisplayCutout} is fully contained within a system bar. Otherwise, the window is * laid out such that it does not overlap with the {@link DisplayCutout} area. * *

    * In practice, this means that if the window did not set FLAG_FULLSCREEN or - * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait. - * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does overlap the + * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait if the cutout + * is at the top edge. Similarly for SYSTEM_UI_FLAG_HIDE_NAVIGATION and a cutout at the + * bottom of the screen. + * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does not overlap the * cutout area. * *

    - * The usual precautions for not overlapping with the status bar are sufficient for ensuring - * that no important content overlaps with the DisplayCutout. + * The usual precautions for not overlapping with the status and navigation bar are + * sufficient for ensuring that no important content overlaps with the DisplayCutout. * * @see DisplayCutout * @see WindowInsets @@ -2260,8 +2262,18 @@ public interface WindowManager extends ViewManager { public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; /** - * The window is always allowed to extend into the {@link DisplayCutout} area, - * even if fullscreen or in landscape. + * @deprecated use {@link #LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES} + * @hide + */ + @Deprecated + public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; + + /** + * The window is always allowed to extend into the {@link DisplayCutout} areas on the short + * edges of the screen. + * + * The window will never extend into a {@link DisplayCutout} area on the long edges of the + * screen. * *

    * The window must make sure that no important content overlaps with the @@ -2270,7 +2282,7 @@ public interface WindowManager extends ViewManager { * @see DisplayCutout * @see WindowInsets#getDisplayCutout() */ - public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; + public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1; /** * The window is never allowed to overlap with the DisplayCutout area. diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index fdd3f7370223936cd2595e4e2839291b55d3e39e..4c437dd446528fdfd7c0eeae0c16d6f3b1870a0d 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -3858,6 +3858,7 @@ public class AccessibilityNodeInfo implements Parcelable { builder.append("; password: ").append(isPassword()); builder.append("; scrollable: ").append(isScrollable()); builder.append("; importantForAccessibility: ").append(isImportantForAccessibility()); + builder.append("; visible: ").append(isVisibleToUser()); builder.append("; actions: ").append(mActions); return builder.toString(); diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 158c2ee0b2d079307a59c8a440b2052fe54bc7cc..5bee87c2af2a4e519aa8294f8858c367554c239d 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -1407,6 +1407,15 @@ public final class AutofillManager { return client; } + /** + * Check if autofill ui is showing, must be called on UI thread. + * @hide + */ + public boolean isAutofillUiShowing() { + final AutofillClient client = mContext.getAutofillClient(); + return client != null && client.autofillClientIsFillUiShowing(); + } + /** @hide */ public void onAuthenticationResult(int authenticationId, Intent data, View focusView) { if (!hasAutofillFeature()) { @@ -2531,6 +2540,10 @@ public final class AutofillManager { ArraySet updatedVisibleTrackedIds = null; ArraySet updatedInvisibleTrackedIds = null; if (client != null) { + if (sVerbose) { + Log.v(TAG, "onVisibleForAutofillChangedLocked(): inv= " + mInvisibleTrackedIds + + " vis=" + mVisibleTrackedIds); + } if (mInvisibleTrackedIds != null) { final ArrayList orderedInvisibleIds = new ArrayList<>(mInvisibleTrackedIds); diff --git a/core/java/android/view/textclassifier/logging/DefaultLogger.java b/core/java/android/view/textclassifier/DefaultLogger.java similarity index 99% rename from core/java/android/view/textclassifier/logging/DefaultLogger.java rename to core/java/android/view/textclassifier/DefaultLogger.java index f510879cf4014af7493fcc1b31ebb0afac8f6db6..b2f4e399da5b6c6da1bc274e5f53d59b3dfd2b43 100644 --- a/core/java/android/view/textclassifier/logging/DefaultLogger.java +++ b/core/java/android/view/textclassifier/DefaultLogger.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.view.textclassifier.logging; +package android.view.textclassifier; import android.annotation.NonNull; import android.content.Context; diff --git a/core/java/android/view/textclassifier/logging/GenerateLinksLogger.java b/core/java/android/view/textclassifier/GenerateLinksLogger.java similarity index 97% rename from core/java/android/view/textclassifier/logging/GenerateLinksLogger.java rename to core/java/android/view/textclassifier/GenerateLinksLogger.java index fb6f205eb4625d6591d4be91a9ecb2d7c62b6cab..73cf43b87ea706023292e3a03338f461752fc221 100644 --- a/core/java/android/view/textclassifier/logging/GenerateLinksLogger.java +++ b/core/java/android/view/textclassifier/GenerateLinksLogger.java @@ -14,14 +14,12 @@ * limitations under the License. */ -package android.view.textclassifier.logging; +package android.view.textclassifier; import android.annotation.Nullable; import android.metrics.LogMaker; import android.util.ArrayMap; import android.util.Log; -import android.view.textclassifier.TextClassifier; -import android.view.textclassifier.TextLinks; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; diff --git a/core/java/android/view/textclassifier/logging/Logger.java b/core/java/android/view/textclassifier/Logger.java similarity index 97% rename from core/java/android/view/textclassifier/logging/Logger.java rename to core/java/android/view/textclassifier/Logger.java index 4448b2b5b494d077f36b891f7b7df28de1edabfd..9c92fd4543e29037c73de2841d275fc7c1078a8a 100644 --- a/core/java/android/view/textclassifier/logging/Logger.java +++ b/core/java/android/view/textclassifier/Logger.java @@ -14,16 +14,13 @@ * limitations under the License. */ -package android.view.textclassifier.logging; +package android.view.textclassifier; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; import android.content.Context; import android.util.Log; -import android.view.textclassifier.TextClassification; -import android.view.textclassifier.TextClassifier; -import android.view.textclassifier.TextSelection; import com.android.internal.util.Preconditions; @@ -97,10 +94,7 @@ public abstract class Logger { } /** - * Writes the selection event. - * - *

    NOTE: This method is designed for subclasses. - * Apps should not call it directly. + * Writes the selection event to a log. */ public abstract void writeEvent(@NonNull SelectionEvent event); diff --git a/wifi/java/android/net/wifi/ScanSettings.aidl b/core/java/android/view/textclassifier/SelectionEvent.aidl similarity index 74% rename from wifi/java/android/net/wifi/ScanSettings.aidl rename to core/java/android/view/textclassifier/SelectionEvent.aidl index ebd2a39ab7c1db11fba2b26415521ab2d6d2a345..10ed16e8df1fb957a82b2c3fcd80ddc92e7a391a 100644 --- a/wifi/java/android/net/wifi/ScanSettings.aidl +++ b/core/java/android/view/textclassifier/SelectionEvent.aidl @@ -1,11 +1,11 @@ -/** - * Copyright (c) 2014, The Android Open Source Project +/* + * 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 + * 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, @@ -14,6 +14,6 @@ * limitations under the License. */ -package android.net.wifi; +package android.view.textclassifier; -parcelable ScanSettings; +parcelable SelectionEvent; diff --git a/core/java/android/view/textclassifier/logging/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java similarity index 70% rename from core/java/android/view/textclassifier/logging/SelectionEvent.java rename to core/java/android/view/textclassifier/SelectionEvent.java index a8de3088d8cc67d4dc888ed56d057b66ad7f50d7..7ac094eda031f273c69692170dffcc0f1804a38c 100644 --- a/core/java/android/view/textclassifier/logging/SelectionEvent.java +++ b/core/java/android/view/textclassifier/SelectionEvent.java @@ -14,10 +14,12 @@ * limitations under the License. */ -package android.view.textclassifier.logging; +package android.view.textclassifier; import android.annotation.IntDef; import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; import android.view.textclassifier.TextClassifier.EntityType; import com.android.internal.util.Preconditions; @@ -25,12 +27,13 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Locale; +import java.util.Objects; /** * A selection event. * Specify index parameters as word token indices. */ -public final class SelectionEvent { +public final class SelectionEvent implements Parcelable { /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -121,9 +124,9 @@ public final class SelectionEvent { private String mSignature; private long mEventTime; private long mDurationSinceSessionStart; - private long mDurationSinceLastEvent; + private long mDurationSincePreviousEvent; private int mEventIndex; - private String mSessionId; + @Nullable private String mSessionId; private int mStart; private int mEnd; private int mSmartStart; @@ -146,6 +149,60 @@ public final class SelectionEvent { mInvocationMethod = invocationMethod; } + private SelectionEvent(Parcel in) { + mAbsoluteStart = in.readInt(); + mAbsoluteEnd = in.readInt(); + mEventType = in.readInt(); + mEntityType = in.readString(); + mWidgetVersion = in.readInt() > 0 ? in.readString() : null; + mPackageName = in.readString(); + mWidgetType = in.readString(); + mInvocationMethod = in.readInt(); + mSignature = in.readString(); + mEventTime = in.readLong(); + mDurationSinceSessionStart = in.readLong(); + mDurationSincePreviousEvent = in.readLong(); + mEventIndex = in.readInt(); + mSessionId = in.readInt() > 0 ? in.readString() : null; + mStart = in.readInt(); + mEnd = in.readInt(); + mSmartStart = in.readInt(); + mSmartEnd = in.readInt(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mAbsoluteStart); + dest.writeInt(mAbsoluteEnd); + dest.writeInt(mEventType); + dest.writeString(mEntityType); + dest.writeInt(mWidgetVersion != null ? 1 : 0); + if (mWidgetVersion != null) { + dest.writeString(mWidgetVersion); + } + dest.writeString(mPackageName); + dest.writeString(mWidgetType); + dest.writeInt(mInvocationMethod); + dest.writeString(mSignature); + dest.writeLong(mEventTime); + dest.writeLong(mDurationSinceSessionStart); + dest.writeLong(mDurationSincePreviousEvent); + dest.writeInt(mEventIndex); + dest.writeInt(mSessionId != null ? 1 : 0); + if (mSessionId != null) { + dest.writeString(mSessionId); + } + dest.writeInt(mStart); + dest.writeInt(mEnd); + dest.writeInt(mSmartStart); + dest.writeInt(mSmartEnd); + } + + @Override + public int describeContents() { + return 0; + } + int getAbsoluteStart() { return mAbsoluteStart; } @@ -240,11 +297,11 @@ public final class SelectionEvent { * in the selection session was triggered. */ public long getDurationSincePreviousEvent() { - return mDurationSinceLastEvent; + return mDurationSincePreviousEvent; } SelectionEvent setDurationSincePreviousEvent(long durationMs) { - this.mDurationSinceLastEvent = durationMs; + this.mDurationSincePreviousEvent = durationMs; return this; } @@ -341,16 +398,67 @@ public final class SelectionEvent { } } + @Override + public int hashCode() { + return Objects.hash(mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType, + mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, mSignature, + mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent, + mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof SelectionEvent)) { + return false; + } + + final SelectionEvent other = (SelectionEvent) obj; + return mAbsoluteStart == other.mAbsoluteStart + && mAbsoluteEnd == other.mAbsoluteEnd + && mEventType == other.mEventType + && Objects.equals(mEntityType, other.mEntityType) + && Objects.equals(mWidgetVersion, other.mWidgetVersion) + && Objects.equals(mPackageName, other.mPackageName) + && Objects.equals(mWidgetType, other.mWidgetType) + && mInvocationMethod == other.mInvocationMethod + && Objects.equals(mSignature, other.mSignature) + && mEventTime == other.mEventTime + && mDurationSinceSessionStart == other.mDurationSinceSessionStart + && mDurationSincePreviousEvent == other.mDurationSincePreviousEvent + && mEventIndex == other.mEventIndex + && Objects.equals(mSessionId, other.mSessionId) + && mStart == other.mStart + && mEnd == other.mEnd + && mSmartStart == other.mSmartStart + && mSmartEnd == other.mSmartEnd; + } + @Override public String toString() { return String.format(Locale.US, "SelectionEvent {absoluteStart=%d, absoluteEnd=%d, eventType=%d, entityType=%s, " - + "widgetVersion=%s, packageName=%s, widgetType=%s, signature=%s, " - + "eventTime=%d, durationSinceSessionStart=%d, durationSinceLastEvent=%d, " - + "eventIndex=%d, sessionId=%s, start=%d, end=%d, smartStart=%d, smartEnd=%d}", + + "widgetVersion=%s, packageName=%s, widgetType=%s, invocationMethod=%s, " + + "signature=%s, eventTime=%d, durationSinceSessionStart=%d, " + + "durationSincePreviousEvent=%d, eventIndex=%d, sessionId=%s, start=%d, end=%d, " + + "smartStart=%d, smartEnd=%d}", mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType, - mWidgetVersion, mPackageName, mWidgetType, mSignature, - mEventTime, mDurationSinceSessionStart, mDurationSinceLastEvent, + mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, mSignature, + mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent, mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd); } + + public static final Creator CREATOR = new Creator() { + @Override + public SelectionEvent createFromParcel(Parcel in) { + return new SelectionEvent(in); + } + + @Override + public SelectionEvent[] newArray(int size) { + return new SelectionEvent[size]; + } + }; } diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java index 2b335fb09c614cc130cc8d85a92f08d2cdd832fe..c783cae4c234202c51aef70162786d80ea56c9c3 100644 --- a/core/java/android/view/textclassifier/SystemTextClassifier.java +++ b/core/java/android/view/textclassifier/SystemTextClassifier.java @@ -29,6 +29,7 @@ import android.service.textclassifier.ITextClassifierService; import android.service.textclassifier.ITextLinksCallback; import android.service.textclassifier.ITextSelectionCallback; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import java.util.concurrent.CountDownLatch; @@ -46,6 +47,12 @@ final class SystemTextClassifier implements TextClassifier { private final TextClassifier mFallback; private final String mPackageName; + private final Object mLoggerLock = new Object(); + @GuardedBy("mLoggerLock") + private Logger.Config mLoggerConfig; + @GuardedBy("mLoggerLock") + private Logger mLogger; + SystemTextClassifier(Context context, TextClassificationConstants settings) throws ServiceManager.ServiceNotFoundException { mManagerService = ITextClassifierService.Stub.asInterface( @@ -58,6 +65,7 @@ final class SystemTextClassifier implements TextClassifier { /** * @inheritDoc */ + @Override @WorkerThread public TextSelection suggestSelection( @NonNull CharSequence text, @@ -84,6 +92,7 @@ final class SystemTextClassifier implements TextClassifier { /** * @inheritDoc */ + @Override @WorkerThread public TextClassification classifyText( @NonNull CharSequence text, @@ -109,6 +118,7 @@ final class SystemTextClassifier implements TextClassifier { /** * @inheritDoc */ + @Override @WorkerThread public TextLinks generateLinks( @NonNull CharSequence text, @Nullable TextLinks.Options options) { @@ -142,11 +152,33 @@ final class SystemTextClassifier implements TextClassifier { * @inheritDoc */ @Override + @WorkerThread public int getMaxGenerateLinksTextLength() { // TODO: retrieve this from the bound service. return mFallback.getMaxGenerateLinksTextLength(); } + @Override + public Logger getLogger(@NonNull Logger.Config config) { + Preconditions.checkNotNull(config); + synchronized (mLoggerLock) { + if (mLogger == null || !config.equals(mLoggerConfig)) { + mLoggerConfig = config; + mLogger = new Logger(config) { + @Override + public void writeEvent(SelectionEvent event) { + try { + mManagerService.onSelectionEvent(event); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + }; + } + } + return mLogger; + } + private static final class TextSelectionCallback extends ITextSelectionCallback.Stub { final ResponseReceiver mReceiver = new ResponseReceiver<>(); diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java index ec40fdd0ffb1c03161cb04bdc795b81c3db312b3..887bebbd97acdfd45d6209d80be45ab2aa5c95a0 100644 --- a/core/java/android/view/textclassifier/TextClassifier.java +++ b/core/java/android/view/textclassifier/TextClassifier.java @@ -28,7 +28,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; import android.util.Slog; -import android.view.textclassifier.logging.Logger; import com.android.internal.util.Preconditions; @@ -324,6 +323,7 @@ public interface TextClassifier { * @see #generateLinks(CharSequence) * @see #generateLinks(CharSequence, TextLinks.Options) */ + @WorkerThread default int getMaxGenerateLinksTextLength() { return Integer.MAX_VALUE; } diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 41f1c69a47edc1cc875cb2b10cce03cd23961d0b..a09982053091b668d06c1c068c19b90c792fa427 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -18,6 +18,7 @@ package android.view.textclassifier; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.WorkerThread; import android.app.SearchManager; import android.content.ComponentName; import android.content.ContentUris; @@ -34,9 +35,6 @@ import android.os.UserManager; import android.provider.Browser; import android.provider.CalendarContract; import android.provider.ContactsContract; -import android.view.textclassifier.logging.DefaultLogger; -import android.view.textclassifier.logging.GenerateLinksLogger; -import android.view.textclassifier.logging.Logger; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; @@ -45,7 +43,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.lang.ref.WeakReference; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; @@ -81,7 +78,6 @@ public final class TextClassifierImpl implements TextClassifier { private final Context mContext; private final TextClassifier mFallback; - private final GenerateLinksLogger mGenerateLinksLogger; private final Object mLock = new Object(); @@ -94,9 +90,9 @@ public final class TextClassifierImpl implements TextClassifier { private final Object mLoggerLock = new Object(); @GuardedBy("mLoggerLock") // Do not access outside this lock. - private WeakReference mLoggerConfig = new WeakReference<>(null); + private Logger.Config mLoggerConfig; @GuardedBy("mLoggerLock") // Do not access outside this lock. - private Logger mLogger; // Should never be null if mLoggerConfig.get() is not null. + private Logger mLogger; private final TextClassificationConstants mSettings; @@ -109,6 +105,7 @@ public final class TextClassifierImpl implements TextClassifier { /** @inheritDoc */ @Override + @WorkerThread public TextSelection suggestSelection( @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex, @Nullable TextSelection.Options options) { @@ -172,6 +169,7 @@ public final class TextClassifierImpl implements TextClassifier { /** @inheritDoc */ @Override + @WorkerThread public TextClassification classifyText( @NonNull CharSequence text, int startIndex, int endIndex, @Nullable TextClassification.Options options) { @@ -207,6 +205,7 @@ public final class TextClassifierImpl implements TextClassifier { /** @inheritDoc */ @Override + @WorkerThread public TextLinks generateLinks( @NonNull CharSequence text, @Nullable TextLinks.Options options) { Utils.validate(text, getMaxGenerateLinksTextLength(), false /* allowInMainThread */); @@ -285,16 +284,17 @@ public final class TextClassifierImpl implements TextClassifier { } } + /** @inheritDoc */ @Override public Logger getLogger(@NonNull Logger.Config config) { Preconditions.checkNotNull(config); synchronized (mLoggerLock) { - if (mLoggerConfig.get() == null || !mLoggerConfig.get().equals(config)) { - mLoggerConfig = new WeakReference<>(config); + if (mLogger == null || !config.equals(mLoggerConfig)) { + mLoggerConfig = config; mLogger = new DefaultLogger(config); } - return mLogger; } + return mLogger; } private TextClassifierImplNative getNative(LocaleList localeList) diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java index 779eefb14c74e6b6d3fbcc7dc0b966359a99464e..886f5c822fb4e6687fb693ce103e558f119c2e3d 100644 --- a/core/java/android/view/textservice/SpellCheckerSession.java +++ b/core/java/android/view/textservice/SpellCheckerSession.java @@ -445,9 +445,15 @@ public class SpellCheckerSession { private void processOrEnqueueTask(SpellCheckerParams scp) { ISpellCheckerSession session; synchronized (this) { + if (scp.mWhat == TASK_CLOSE && (mState == STATE_CLOSED_AFTER_CONNECTION + || mState == STATE_CLOSED_BEFORE_CONNECTION)) { + // It is OK to call SpellCheckerSession#close() multiple times. + // Don't output confusing/misleading warning messages. + return; + } if (mState != STATE_WAIT_CONNECTION && mState != STATE_CONNECTED) { Log.e(TAG, "ignoring processOrEnqueueTask due to unexpected mState=" - + taskToString(scp.mWhat) + + stateToString(mState) + " scp.mWhat=" + taskToString(scp.mWhat)); return; } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 5d3f1c9288cd0479b2e3eab435b43d40f8c134dc..5178a97e6b68ac18b08b9ced4fcfe28880000ee6 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: *

      * <link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio:1.5)" href="hdpi.css" />
    - *

    The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ration of 1.5, + *

    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. * * @@ -2906,6 +2906,11 @@ public class WebView extends AbsoluteLayout mProvider.getViewDelegate().autofill(values); } + @Override + public boolean isVisibleToUserForAutofill(int virtualId) { + return mProvider.getViewDelegate().isVisibleToUserForAutofill(virtualId); + } + /** @hide */ @Override public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java index a474a8580b694b2d2451562b93b8f2727a2cd26e..00e782bd5046ccc7d062e2f969af2a04e3e9852e 100644 --- a/core/java/android/webkit/WebViewProvider.java +++ b/core/java/android/webkit/WebViewProvider.java @@ -329,13 +329,16 @@ public interface WebViewProvider { public void onProvideVirtualStructure(android.view.ViewStructure structure); - @SuppressWarnings("unused") - public default void onProvideAutofillVirtualStructure(android.view.ViewStructure structure, - int flags) { + default void onProvideAutofillVirtualStructure( + @SuppressWarnings("unused") android.view.ViewStructure structure, + @SuppressWarnings("unused") int flags) { } - @SuppressWarnings("unused") - public default void autofill(SparseArrayvalues) { + default void autofill(@SuppressWarnings("unused") SparseArray values) { + } + + default boolean isVisibleToUserForAutofill(@SuppressWarnings("unused") int virtualId) { + return true; // true is the default value returned by View.isVisibleToUserForAutofill() } public AccessibilityNodeProvider getAccessibilityNodeProvider(); diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java index 07593a5122160406a7db336ac96cc5905344fe1f..49e11b8baf51f4b6bcdc0ead8acf3ce5919a7179 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/Editor.java b/core/java/android/widget/Editor.java index 27dd39b3224f809ad33a7c40fd75c80029ae6667..92285c77e61cdf030ba50e1159d4fb630d887dfa 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -17,6 +17,7 @@ package android.widget; import android.R; +import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -100,6 +101,7 @@ import android.view.ViewGroup.LayoutParams; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.animation.LinearInterpolator; import android.view.inputmethod.CorrectionInfo; import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; @@ -201,11 +203,11 @@ public class Editor { private final boolean mHapticTextHandleEnabled; - private final Magnifier mMagnifier; + private final MagnifierMotionAnimator mMagnifierAnimator; private final Runnable mUpdateMagnifierRunnable = new Runnable() { @Override public void run() { - mMagnifier.update(); + mMagnifierAnimator.update(); } }; // Update the magnifier contents whenever anything in the view hierarchy is updated. @@ -216,7 +218,7 @@ public class Editor { new ViewTreeObserver.OnDrawListener() { @Override public void onDraw() { - if (mMagnifier != null) { + if (mMagnifierAnimator != null) { // Posting the method will ensure that updating the magnifier contents will // happen right after the rendering of the current frame. mTextView.post(mUpdateMagnifierRunnable); @@ -372,7 +374,9 @@ public class Editor { mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean( com.android.internal.R.bool.config_enableHapticTextHandle); - mMagnifier = FLAG_USE_MAGNIFIER ? new Magnifier(mTextView) : null; + if (FLAG_USE_MAGNIFIER) { + mMagnifierAnimator = new MagnifierMotionAnimator(new Magnifier(mTextView)); + } } ParcelableParcel saveInstanceState() { @@ -4310,6 +4314,88 @@ public class Editor { } } + private static class MagnifierMotionAnimator { + private static final long DURATION = 100 /* miliseconds */; + + // The magnifier being animated. + private final Magnifier mMagnifier; + // A value animator used to animate the magnifier. + private final ValueAnimator mAnimator; + + // Whether the magnifier is currently visible. + private boolean mMagnifierIsShowing; + // The coordinates of the magnifier when the currently running animation started. + private float mAnimationStartX; + private float mAnimationStartY; + // The coordinates of the magnifier in the latest animation frame. + private float mAnimationCurrentX; + private float mAnimationCurrentY; + // The latest coordinates the motion animator was asked to #show() the magnifier at. + private float mLastX; + private float mLastY; + + private MagnifierMotionAnimator(final Magnifier magnifier) { + mMagnifier = magnifier; + // Prepare the animator used to run the motion animation. + mAnimator = ValueAnimator.ofFloat(0, 1); + mAnimator.setDuration(DURATION); + mAnimator.setInterpolator(new LinearInterpolator()); + mAnimator.addUpdateListener((animation) -> { + // Interpolate to find the current position of the magnifier. + mAnimationCurrentX = mAnimationStartX + + (mLastX - mAnimationStartX) * animation.getAnimatedFraction(); + mAnimationCurrentY = mAnimationStartY + + (mLastY - mAnimationStartY) * animation.getAnimatedFraction(); + mMagnifier.show(mAnimationCurrentX, mAnimationCurrentY); + }); + } + + /** + * Shows the magnifier at a new position. + * If the y coordinate is different from the previous y coordinate + * (probably corresponding to a line jump in the text), a short + * animation is added to the jump. + */ + private void show(final float x, final float y) { + final boolean startNewAnimation = mMagnifierIsShowing && y != mLastY; + + if (startNewAnimation) { + if (mAnimator.isRunning()) { + mAnimator.cancel(); + mAnimationStartX = mAnimationCurrentX; + mAnimationStartY = mAnimationCurrentY; + } else { + mAnimationStartX = mLastX; + mAnimationStartY = mLastY; + } + mAnimator.start(); + } else { + if (!mAnimator.isRunning()) { + mMagnifier.show(x, y); + } + } + mLastX = x; + mLastY = y; + mMagnifierIsShowing = true; + } + + /** + * Updates the content of the magnifier. + */ + private void update() { + mMagnifier.update(); + } + + /** + * Dismisses the magnifier, or does nothing if it is already dismissed. + */ + private void dismiss() { + mMagnifier.dismiss(); + mAnimator.cancel(); + mMagnifierIsShowing = false; + } + } + @VisibleForTesting public abstract class HandleView extends View implements TextViewPositionListener { protected Drawable mDrawable; @@ -4660,16 +4746,23 @@ public class Editor { final int trigger = getMagnifierHandleTrigger(); final int offset; + final int otherHandleOffset; switch (trigger) { - case MagnifierHandleTrigger.INSERTION: // Fall through. + case MagnifierHandleTrigger.INSERTION: + offset = mTextView.getSelectionStart(); + otherHandleOffset = -1; + break; case MagnifierHandleTrigger.SELECTION_START: offset = mTextView.getSelectionStart(); + otherHandleOffset = mTextView.getSelectionEnd(); break; case MagnifierHandleTrigger.SELECTION_END: offset = mTextView.getSelectionEnd(); + otherHandleOffset = mTextView.getSelectionStart(); break; default: offset = -1; + otherHandleOffset = -1; break; } @@ -4679,22 +4772,39 @@ public class Editor { final Layout layout = mTextView.getLayout(); final int lineNumber = layout.getLineForOffset(offset); - - // Horizontally move the magnifier smoothly but clamp inside the current line. + // Compute whether the selection handles are currently on the same line, and, + // in this particular case, whether the selected text is right to left. + final boolean sameLineSelection = otherHandleOffset != -1 + && lineNumber == layout.getLineForOffset(otherHandleOffset); + final boolean rtl = sameLineSelection + && (offset < otherHandleOffset) + != (getHorizontal(mTextView.getLayout(), offset) + < getHorizontal(mTextView.getLayout(), otherHandleOffset)); + + // Horizontally move the magnifier smoothly, clamp inside the current line / selection. final int[] textViewLocationOnScreen = new int[2]; mTextView.getLocationOnScreen(textViewLocationOnScreen); final float touchXInView = event.getRawX() - textViewLocationOnScreen[0]; - final float lineLeft = mTextView.getLayout().getLineLeft(lineNumber) - + mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); - final float lineRight = mTextView.getLayout().getLineRight(lineNumber) - + mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); - final float contentWidth = Math.round(mMagnifier.getWidth() / mMagnifier.getZoom()); - if (touchXInView < lineLeft - contentWidth / 2 - || touchXInView > lineRight + contentWidth / 2) { - // The touch is too out of the bounds of the current line, so hide the magnifier. + float leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); + float rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); + if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_END) ^ rtl)) { + leftBound += getHorizontal(mTextView.getLayout(), otherHandleOffset); + } else { + leftBound += mTextView.getLayout().getLineLeft(lineNumber); + } + if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START) ^ rtl)) { + rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset); + } else { + rightBound += mTextView.getLayout().getLineRight(lineNumber); + } + final float contentWidth = Math.round(mMagnifierAnimator.mMagnifier.getWidth() + / mMagnifierAnimator.mMagnifier.getZoom()); + if (touchXInView < leftBound - contentWidth / 2 + || touchXInView > rightBound + contentWidth / 2) { + // The touch is too far from the current line / selection, so hide the magnifier. return false; } - showPosInView.x = Math.max(lineLeft, Math.min(lineRight, touchXInView)); + showPosInView.x = Math.max(leftBound, Math.min(rightBound, touchXInView)); // Vertically snap to middle of current line. showPosInView.y = (mTextView.getLayout().getLineTop(lineNumber) @@ -4705,7 +4815,7 @@ public class Editor { } protected final void updateMagnifier(@NonNull final MotionEvent event) { - if (mMagnifier == null) { + if (mMagnifierAnimator == null) { return; } @@ -4716,15 +4826,15 @@ public class Editor { mRenderCursorRegardlessTiming = true; mTextView.invalidateCursorPath(); suspendBlink(); - mMagnifier.show(showPosInView.x, showPosInView.y); + mMagnifierAnimator.show(showPosInView.x, showPosInView.y); } else { dismissMagnifier(); } } protected final void dismissMagnifier() { - if (mMagnifier != null) { - mMagnifier.dismiss(); + if (mMagnifierAnimator != null) { + mMagnifierAnimator.dismiss(); mRenderCursorRegardlessTiming = false; resumeBlink(); } diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 3db149a442de647c1dae9e0866b9587be382a7de..e2601dcb91aca1dc4e4ff9a83384b4b39790cdeb 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -23,6 +23,7 @@ import android.annotation.TestApi; import android.annotation.UiThread; import android.content.Context; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Outline; @@ -34,6 +35,7 @@ import android.graphics.Rect; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; +import android.view.ContextThemeWrapper; import android.view.Display; import android.view.DisplayListCanvas; import android.view.LayoutInflater; @@ -49,6 +51,7 @@ import android.view.View; import android.view.ViewParent; import android.view.ViewRootImpl; +import com.android.internal.R; import com.android.internal.util.Preconditions; /** @@ -83,6 +86,8 @@ public final class Magnifier { private final int mBitmapHeight; // The elevation of the window containing the magnifier. private final float mWindowElevation; + // The corner radius of the window containing the magnifier. + private final float mWindowCornerRadius; // The center coordinates of the content that is to be magnified. private final Point mCenterZoomCoords = new Point(); // Variables holding previous states, used for detecting redundant calls and invalidation. @@ -104,17 +109,13 @@ public final class Magnifier { public Magnifier(@NonNull View view) { mView = Preconditions.checkNotNull(view); final Context context = mView.getContext(); - final View content = LayoutInflater.from(context).inflate( - com.android.internal.R.layout.magnifier, null); - content.findViewById(com.android.internal.R.id.magnifier_inner).setClipToOutline(true); - mWindowWidth = context.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.magnifier_width); - mWindowHeight = context.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.magnifier_height); - mWindowElevation = context.getResources().getDimension( - com.android.internal.R.dimen.magnifier_elevation); - mZoom = context.getResources().getFloat( - com.android.internal.R.dimen.magnifier_zoom_scale); + final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null); + content.findViewById(R.id.magnifier_inner).setClipToOutline(true); + mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width); + mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height); + mWindowElevation = context.getResources().getDimension(R.dimen.magnifier_elevation); + mWindowCornerRadius = getDeviceDefaultDialogCornerRadius(); + mZoom = context.getResources().getFloat(R.dimen.magnifier_zoom_scale); mBitmapWidth = Math.round(mWindowWidth / mZoom); mBitmapHeight = Math.round(mWindowHeight / mZoom); // The view's surface coordinates will not be updated until the magnifier is first shown. @@ -125,6 +126,21 @@ public final class Magnifier { sPixelCopyHandlerThread.start(); } + /** + * Returns the device default theme dialog corner radius attribute. + * We retrieve this from the device default theme to avoid + * using the values set in the custom application themes. + */ + private float getDeviceDefaultDialogCornerRadius() { + final Context deviceDefaultContext = + new ContextThemeWrapper(mView.getContext(), R.style.Theme_DeviceDefault); + final TypedArray ta = deviceDefaultContext.obtainStyledAttributes( + new int[]{android.R.attr.dialogCornerRadius}); + final float dialogCornerRadius = ta.getDimension(0, 0); + ta.recycle(); + return dialogCornerRadius; + } + /** * Shows the magnifier on the screen. * @@ -178,7 +194,8 @@ public final class Magnifier { if (mWindow == null) { synchronized (mLock) { mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(), - getValidViewSurface(), mWindowWidth, mWindowHeight, mWindowElevation, + getValidViewSurface(), + mWindowWidth, mWindowHeight, mWindowElevation, mWindowCornerRadius, Handler.getMain() /* draw the magnifier on the UI thread */, mLock, mCallback); } @@ -271,7 +288,7 @@ public final class Magnifier { // Compute the position of the magnifier window. Again, this has to be relative to the // surface of the magnified view, as this surface is the parent of the magnifier surface. final int verticalOffset = mView.getContext().getResources().getDimensionPixelSize( - com.android.internal.R.dimen.magnifier_offset); + R.dimen.magnifier_offset); mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2; mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalOffset; } @@ -393,7 +410,7 @@ public final class Magnifier { InternalPopupWindow(final Context context, final Display display, final Surface parentSurface, - final int width, final int height, final float elevation, + final int width, final int height, final float elevation, final float cornerRadius, final Handler handler, final Object lock, final Callback callback) { mDisplay = display; mLock = lock; @@ -424,7 +441,8 @@ public final class Magnifier { ); mBitmapRenderNode = createRenderNodeForBitmap( "magnifier content", - elevation + elevation, + cornerRadius ); final DisplayListCanvas canvas = mRenderer.getRootNode().start(width, height); @@ -442,7 +460,8 @@ public final class Magnifier { mFrameDrawScheduled = false; } - private RenderNode createRenderNodeForBitmap(final String name, final float elevation) { + private RenderNode createRenderNodeForBitmap(final String name, + final float elevation, final float cornerRadius) { final RenderNode bitmapRenderNode = RenderNode.create(name, null); // Define the position of the bitmap in the parent render node. The surface regions @@ -452,7 +471,7 @@ public final class Magnifier { bitmapRenderNode.setElevation(elevation); final Outline outline = new Outline(); - outline.setRoundRect(0, 0, mContentWidth, mContentHeight, 3); + outline.setRoundRect(0, 0, mContentWidth, mContentHeight, cornerRadius); outline.setAlpha(1.0f); bitmapRenderNode.setOutline(outline); bitmapRenderNode.setClipToOutline(true); @@ -658,8 +677,8 @@ public final class Magnifier { final Resources resources = Resources.getSystem(); final float density = resources.getDisplayMetrics().density; final PointF size = new PointF(); - size.x = resources.getDimension(com.android.internal.R.dimen.magnifier_width) / density; - size.y = resources.getDimension(com.android.internal.R.dimen.magnifier_height) / density; + size.x = resources.getDimension(R.dimen.magnifier_width) / density; + size.y = resources.getDimension(R.dimen.magnifier_height) / density; return size; } diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 75fc5386410158643f8a58b2697ab35650978893..bbdf15c871bb93688078c4ae5890869e085599b5 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -1182,12 +1182,12 @@ public class RelativeLayout extends ViewGroup { * determine where to position the view on the screen. If the view is not contained * within a relative layout, these attributes are ignored. * - * See the + * See the * Relative Layout guide for example code demonstrating how to use relative layout’s * layout parameters in a layout XML. * * To learn more about layout parameters and how they differ from typical view attributes, - * see the + * see the * Layouts guide. * * diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java index 8e93078fb1b56dfa9624c7cd73828bd42f059c30..be8c34c53ae69b644f2b0c3f9bc065a74be74230 100644 --- a/core/java/android/widget/SelectionActionModeHelper.java +++ b/core/java/android/widget/SelectionActionModeHelper.java @@ -33,13 +33,13 @@ import android.text.Spannable; import android.text.TextUtils; import android.util.Log; import android.view.ActionMode; +import android.view.textclassifier.Logger; +import android.view.textclassifier.SelectionEvent; import android.view.textclassifier.TextClassification; import android.view.textclassifier.TextClassificationConstants; import android.view.textclassifier.TextClassificationManager; import android.view.textclassifier.TextClassifier; import android.view.textclassifier.TextSelection; -import android.view.textclassifier.logging.Logger; -import android.view.textclassifier.logging.SelectionEvent; import android.widget.Editor.SelectionModifierCursorController; import com.android.internal.annotations.VisibleForTesting; @@ -648,6 +648,9 @@ public final class SelectionActionModeHelper { * Part selection of a word e.g. "or" is counted as selecting the * entire word i.e. equivalent to "York", and each special character is counted as a word, e.g. * "," is at [2, 3). Whitespaces are ignored. + * + * NOTE that the definition of a word is defined by the TextClassifier's Logger's token + * iterator. */ private static final class SelectionMetricsLogger { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 6fe64a03a95c7bdc013c567a4cd42f90316bf40e..72c8426482aa4e153cd182b4b4458b3df1e4e76e 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 @@ -1917,19 +1918,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Calculate the sizes set based on minimum size, maximum size and step size if we do // not have a predefined set of sizes or if the current sizes array is empty. if (!mHasPresetAutoSizeValues || mAutoSizeTextSizesInPx.length == 0) { - int autoSizeValuesLength = 1; - float currentSize = Math.round(mAutoSizeMinTextSizeInPx); - while (Math.round(currentSize + mAutoSizeStepGranularityInPx) - <= Math.round(mAutoSizeMaxTextSizeInPx)) { - autoSizeValuesLength++; - currentSize += mAutoSizeStepGranularityInPx; - } - - int[] autoSizeTextSizesInPx = new int[autoSizeValuesLength]; - float sizeToAdd = mAutoSizeMinTextSizeInPx; + final int autoSizeValuesLength = ((int) Math.floor((mAutoSizeMaxTextSizeInPx + - mAutoSizeMinTextSizeInPx) / mAutoSizeStepGranularityInPx)) + 1; + final int[] autoSizeTextSizesInPx = new int[autoSizeValuesLength]; for (int i = 0; i < autoSizeValuesLength; i++) { - autoSizeTextSizesInPx[i] = Math.round(sizeToAdd); - sizeToAdd += mAutoSizeStepGranularityInPx; + autoSizeTextSizesInPx[i] = Math.round( + mAutoSizeMinTextSizeInPx + (i * mAutoSizeStepGranularityInPx)); } mAutoSizeTextSizesInPx = cleanupAutoSizePresetSizes(autoSizeTextSizesInPx); } diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl index 1bee6924454d9c513947455b0e68949fc1d25c38..93730df7dd4760ac1f8f3152e17d562de37cdd20 100644 --- a/core/java/com/android/internal/app/ISoundTriggerService.aidl +++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl @@ -17,8 +17,10 @@ package com.android.internal.app; import android.app.PendingIntent; +import android.content.ComponentName; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger; +import android.os.Bundle; import android.os.ParcelUuid; /** @@ -44,9 +46,15 @@ interface ISoundTriggerService { int startRecognitionForIntent(in ParcelUuid soundModelId, in PendingIntent callbackIntent, in SoundTrigger.RecognitionConfig config); + + int startRecognitionForService(in ParcelUuid soundModelId, in Bundle params, + in ComponentName callbackIntent,in SoundTrigger.RecognitionConfig config); + + /** For both ...Intent and ...Service based usage */ int stopRecognitionForIntent(in ParcelUuid soundModelId); int unloadSoundModel(in ParcelUuid soundModelId); + /** For both ...Intent and ...Service based usage */ boolean isRecognitionActive(in ParcelUuid parcelUuid); } diff --git a/core/java/com/android/internal/backup/LocalTransportParameters.java b/core/java/com/android/internal/backup/LocalTransportParameters.java index 390fae96f810217fc7fe556237d64c6427887e43..154e79d4f7efd539bd2a9796ebdab3c9d703daeb 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/inputmethod/InputMethodSubtypeHandle.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java deleted file mode 100644 index 04d7f9b2c9c0966aec6f89672c75ebcd2a7b73a0..0000000000000000000000000000000000000000 --- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.inputmethod; - -import android.annotation.Nullable; -import android.text.TextUtils; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; - -import java.util.Objects; - -public class InputMethodSubtypeHandle { - private final String mInputMethodId; - private final int mSubtypeId; - - public InputMethodSubtypeHandle(InputMethodInfo info, @Nullable InputMethodSubtype subtype) { - mInputMethodId = info.getId(); - if (subtype != null) { - mSubtypeId = subtype.hashCode(); - } else { - mSubtypeId = InputMethodUtils.NOT_A_SUBTYPE_ID; - } - } - - public InputMethodSubtypeHandle(String inputMethodId, int subtypeId) { - mInputMethodId = inputMethodId; - mSubtypeId = subtypeId; - } - - public String getInputMethodId() { - return mInputMethodId; - } - - public int getSubtypeId() { - return mSubtypeId; - } - - @Override - public boolean equals(Object o) { - if (o == null || !(o instanceof InputMethodSubtypeHandle)) { - return false; - } - InputMethodSubtypeHandle other = (InputMethodSubtypeHandle) o; - return TextUtils.equals(mInputMethodId, other.getInputMethodId()) - && mSubtypeId == other.getSubtypeId(); - } - - @Override - public int hashCode() { - return Objects.hashCode(mInputMethodId) * 31 + mSubtypeId; - } - - @Override - public String toString() { - return "InputMethodSubtypeHandle{mInputMethodId=" + mInputMethodId - + ", mSubtypeId=" + mSubtypeId + "}"; - } -} diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java index 44adbb22eb7ef4bdf44191e44d14db1422085e6a..21b7d25d2ebecbe5b3b481c7236b35c902404465 100644 --- a/core/java/com/android/internal/notification/SystemNotificationChannels.java +++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java @@ -50,14 +50,18 @@ 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); List channelsList = new ArrayList(); - channelsList.add(new NotificationChannel( + final NotificationChannel keyboard = new NotificationChannel( VIRTUAL_KEYBOARD, context.getString(R.string.notification_channel_virtual_keyboard), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + keyboard.setBypassDnd(true); + keyboard.setBlockableSystem(true); + channelsList.add(keyboard); final NotificationChannel physicalKeyboardChannel = new NotificationChannel( PHYSICAL_KEYBOARD, @@ -65,81 +69,105 @@ public class SystemNotificationChannels { NotificationManager.IMPORTANCE_DEFAULT); physicalKeyboardChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, Notification.AUDIO_ATTRIBUTES_DEFAULT); + physicalKeyboardChannel.setBlockableSystem(true); channelsList.add(physicalKeyboardChannel); - channelsList.add(new NotificationChannel( + final NotificationChannel security = new NotificationChannel( SECURITY, context.getString(R.string.notification_channel_security), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + security.setBypassDnd(true); + channelsList.add(security); - channelsList.add(new NotificationChannel( + final NotificationChannel car = new NotificationChannel( CAR_MODE, context.getString(R.string.notification_channel_car_mode), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + car.setBlockableSystem(true); + car.setBypassDnd(true); + channelsList.add(car); channelsList.add(newAccountChannel(context)); - channelsList.add(new NotificationChannel( + final NotificationChannel developer = new NotificationChannel( DEVELOPER, context.getString(R.string.notification_channel_developer), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + developer.setBypassDnd(true); + developer.setBlockableSystem(true); + channelsList.add(developer); - channelsList.add(new NotificationChannel( + final NotificationChannel updates = new NotificationChannel( UPDATES, context.getString(R.string.notification_channel_updates), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + updates.setBypassDnd(true); + channelsList.add(updates); - channelsList.add(new NotificationChannel( + final NotificationChannel network = new NotificationChannel( NETWORK_STATUS, context.getString(R.string.notification_channel_network_status), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + network.setBypassDnd(true); + channelsList.add(network); final NotificationChannel networkAlertsChannel = new NotificationChannel( NETWORK_ALERTS, context.getString(R.string.notification_channel_network_alerts), NotificationManager.IMPORTANCE_HIGH); - networkAlertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, - Notification.AUDIO_ATTRIBUTES_DEFAULT); + networkAlertsChannel.setBypassDnd(true); + networkAlertsChannel.setBlockableSystem(true); channelsList.add(networkAlertsChannel); - channelsList.add(new NotificationChannel( + final NotificationChannel networkAvailable = new NotificationChannel( NETWORK_AVAILABLE, context.getString(R.string.notification_channel_network_available), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + networkAvailable.setBlockableSystem(true); + networkAvailable.setBypassDnd(true); + channelsList.add(networkAvailable); - channelsList.add(new NotificationChannel( + final NotificationChannel vpn = new NotificationChannel( VPN, context.getString(R.string.notification_channel_vpn), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + vpn.setBypassDnd(true); + channelsList.add(vpn); - channelsList.add(new NotificationChannel( + final NotificationChannel deviceAdmin = new NotificationChannel( DEVICE_ADMIN, context.getString(R.string.notification_channel_device_admin), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + deviceAdmin.setBypassDnd(true); + channelsList.add(deviceAdmin); final NotificationChannel alertsChannel = new NotificationChannel( ALERTS, context.getString(R.string.notification_channel_alerts), NotificationManager.IMPORTANCE_DEFAULT); - alertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, - Notification.AUDIO_ATTRIBUTES_DEFAULT); + alertsChannel.setBypassDnd(true); channelsList.add(alertsChannel); - channelsList.add(new NotificationChannel( + final NotificationChannel retail = new NotificationChannel( RETAIL_MODE, context.getString(R.string.notification_channel_retail_mode), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + retail.setBypassDnd(true); + channelsList.add(retail); - channelsList.add(new NotificationChannel( + final NotificationChannel usb = new NotificationChannel( USB, context.getString(R.string.notification_channel_usb), - NotificationManager.IMPORTANCE_MIN)); + NotificationManager.IMPORTANCE_MIN); + usb.setBypassDnd(true); + channelsList.add(usb); NotificationChannel foregroundChannel = new NotificationChannel( FOREGROUND_SERVICE, context.getString(R.string.notification_channel_foreground_service), NotificationManager.IMPORTANCE_LOW); foregroundChannel.setBlockableSystem(true); + foregroundChannel.setBypassDnd(true); channelsList.add(foregroundChannel); NotificationChannel heavyWeightChannel = new NotificationChannel( @@ -151,13 +179,21 @@ public class SystemNotificationChannels { .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT) .build()); + heavyWeightChannel.setBypassDnd(true); channelsList.add(heavyWeightChannel); NotificationChannel systemChanges = new NotificationChannel(SYSTEM_CHANGES, context.getString(R.string.notification_channel_system_changes), NotificationManager.IMPORTANCE_LOW); + systemChanges.setBypassDnd(true); channelsList.add(systemChanges); + NotificationChannel dndChanges = new NotificationChannel(DO_NOT_DISTURB, + context.getString(R.string.notification_channel_do_not_disturb), + NotificationManager.IMPORTANCE_LOW); + dndChanges.setBypassDnd(true); + channelsList.add(dndChanges); + nm.createNotificationChannels(channelsList); } @@ -172,10 +208,12 @@ public class SystemNotificationChannels { } private static NotificationChannel newAccountChannel(Context context) { - return new NotificationChannel( + final NotificationChannel acct = new NotificationChannel( ACCOUNT, context.getString(R.string.notification_channel_account), NotificationManager.IMPORTANCE_LOW); + acct.setBypassDnd(true); + return acct; } private SystemNotificationChannels() {} diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 4ab2fecbe9645af08f5ff44cf97f4be8aa1e2157..06230c1f814569d2b41b23323130ffcd56822d52 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -33,9 +33,6 @@ import android.net.wifi.WifiManager; import android.os.BatteryManager; import android.os.BatteryStats; import android.os.Build; -import android.os.connectivity.CellularBatteryStats; -import android.os.connectivity.WifiBatteryStats; -import android.os.connectivity.GpsBatteryStats; import android.os.FileUtils; import android.os.Handler; import android.os.IBatteryPropertiesRegistrar; @@ -53,6 +50,9 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.WorkSource; import android.os.WorkSource.WorkChain; +import android.os.connectivity.CellularBatteryStats; +import android.os.connectivity.GpsBatteryStats; +import android.os.connectivity.WifiBatteryStats; import android.provider.Settings; import android.telephony.DataConnectionRealTimeInfo; import android.telephony.ModemActivityInfo; @@ -90,8 +90,8 @@ import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; import com.android.internal.util.XmlUtils; -import java.util.List; import libcore.util.EmptyArray; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -109,11 +109,11 @@ import java.util.Arrays; import java.util.Calendar; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.Queue; import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; @@ -234,11 +234,15 @@ public class BatteryStatsImpl extends BatteryStats { protected final SparseIntArray mPendingUids = new SparseIntArray(); @GuardedBy("this") - private long mNumCpuTimeReads; + private long mNumSingleUidCpuTimeReads; @GuardedBy("this") - private long mNumBatchedCpuTimeReads; + private long mNumBatchedSingleUidCpuTimeReads; @GuardedBy("this") private long mCpuTimeReadsTrackingStartTime = SystemClock.uptimeMillis(); + @GuardedBy("this") + private int mNumUidsRemoved; + @GuardedBy("this") + private int mNumAllUidCpuTimeReads; /** Container for Resource Power Manager stats. Updated by updateRpmStatsLocked. */ private final RpmStats mTmpRpmStats = new RpmStats(); @@ -246,6 +250,67 @@ public class BatteryStatsImpl extends BatteryStats { private static final long RPM_STATS_UPDATE_FREQ_MS = 1000; /** Last time that RPM stats were updated by updateRpmStatsLocked. */ private long mLastRpmStatsUpdateTimeMs = -RPM_STATS_UPDATE_FREQ_MS; + /** + * Use a queue to delay removing UIDs from {@link KernelUidCpuTimeReader}, + * {@link KernelUidCpuActiveTimeReader}, {@link KernelUidCpuClusterTimeReader}, + * {@link KernelUidCpuFreqTimeReader} and from the Kernel. + * + * Isolated and invalid UID info must be removed to conserve memory. However, STATSD and + * Batterystats both need to access UID cpu time. To resolve this race condition, only + * Batterystats shall remove UIDs, and a delay {@link Constants#UID_REMOVE_DELAY_MS} is + * implemented so that STATSD can capture those UID times before they are deleted. + */ + @GuardedBy("this") + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected Queue mPendingRemovedUids = new LinkedList<>(); + + @VisibleForTesting + public final class UidToRemove { + int startUid; + int endUid; + long timeAddedInQueue; + + /** Remove just one UID */ + public UidToRemove(int uid, long timestamp) { + this(uid, uid, timestamp); + } + + /** Remove a range of UIDs, startUid must be smaller than endUid. */ + public UidToRemove(int startUid, int endUid, long timestamp) { + this.startUid = startUid; + this.endUid = endUid; + timeAddedInQueue = timestamp; + } + + void remove() { + if (startUid == endUid) { + mKernelUidCpuTimeReader.removeUid(startUid); + mKernelUidCpuFreqTimeReader.removeUid(startUid); + if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) { + mKernelUidCpuActiveTimeReader.removeUid(startUid); + mKernelUidCpuClusterTimeReader.removeUid(startUid); + } + if (mKernelSingleUidTimeReader != null) { + mKernelSingleUidTimeReader.removeUid(startUid); + } + mNumUidsRemoved++; + } else if (startUid < endUid) { + mKernelUidCpuFreqTimeReader.removeUidsInRange(startUid, endUid); + mKernelUidCpuTimeReader.removeUidsInRange(startUid, endUid); + if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) { + mKernelUidCpuActiveTimeReader.removeUidsInRange(startUid, endUid); + mKernelUidCpuClusterTimeReader.removeUidsInRange(startUid, endUid); + } + if (mKernelSingleUidTimeReader != null) { + mKernelSingleUidTimeReader.removeUidsInRange(startUid, endUid); + } + // Treat as one. We don't know how many uids there are in between. + mNumUidsRemoved++; + } else { + Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid); + } + } + } public interface BatteryCallback { public void batteryNeedsCpuUpdate(); @@ -376,6 +441,14 @@ public class BatteryStatsImpl extends BatteryStats { } } + public void clearPendingRemovedUids() { + long cutOffTime = mClocks.elapsedRealtime() - mConstants.UID_REMOVE_DELAY_MS; + while (!mPendingRemovedUids.isEmpty() + && mPendingRemovedUids.peek().timeAddedInQueue < cutOffTime) { + mPendingRemovedUids.poll().remove(); + } + } + public void copyFromAllUidsCpuTimes() { synchronized (BatteryStatsImpl.this) { copyFromAllUidsCpuTimes( @@ -3961,12 +4034,7 @@ public class BatteryStatsImpl extends BatteryStats { u.removeIsolatedUid(isolatedUid); mIsolatedUids.removeAt(idx); } - mKernelUidCpuTimeReader.removeUid(isolatedUid); - mKernelUidCpuFreqTimeReader.removeUid(isolatedUid); - if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) { - mKernelUidCpuActiveTimeReader.removeUid(isolatedUid); - mKernelUidCpuClusterTimeReader.removeUid(isolatedUid); - } + mPendingRemovedUids.add(new UidToRemove(isolatedUid, mClocks.elapsedRealtime())); } public int mapUid(int uid) { @@ -5284,69 +5352,15 @@ public class BatteryStatsImpl extends BatteryStats { } public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData) { + // BatteryStats uses 0 to represent no network type. + // Telephony does not have a concept of no network type, and uses 0 to represent unknown. + // Unknown is included in DATA_CONNECTION_OTHER. int bin = DATA_CONNECTION_NONE; if (hasData) { - switch (dataType) { - case TelephonyManager.NETWORK_TYPE_EDGE: - bin = DATA_CONNECTION_EDGE; - break; - case TelephonyManager.NETWORK_TYPE_GPRS: - bin = DATA_CONNECTION_GPRS; - break; - case TelephonyManager.NETWORK_TYPE_UMTS: - bin = DATA_CONNECTION_UMTS; - break; - case TelephonyManager.NETWORK_TYPE_CDMA: - bin = DATA_CONNECTION_CDMA; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_0: - bin = DATA_CONNECTION_EVDO_0; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_A: - bin = DATA_CONNECTION_EVDO_A; - break; - case TelephonyManager.NETWORK_TYPE_1xRTT: - bin = DATA_CONNECTION_1xRTT; - break; - case TelephonyManager.NETWORK_TYPE_HSDPA: - bin = DATA_CONNECTION_HSDPA; - break; - case TelephonyManager.NETWORK_TYPE_HSUPA: - bin = DATA_CONNECTION_HSUPA; - break; - case TelephonyManager.NETWORK_TYPE_HSPA: - bin = DATA_CONNECTION_HSPA; - break; - case TelephonyManager.NETWORK_TYPE_IDEN: - bin = DATA_CONNECTION_IDEN; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_B: - bin = DATA_CONNECTION_EVDO_B; - break; - case TelephonyManager.NETWORK_TYPE_LTE: - bin = DATA_CONNECTION_LTE; - break; - case TelephonyManager.NETWORK_TYPE_EHRPD: - bin = DATA_CONNECTION_EHRPD; - break; - case TelephonyManager.NETWORK_TYPE_HSPAP: - bin = DATA_CONNECTION_HSPAP; - break; - case TelephonyManager.NETWORK_TYPE_GSM: - bin = DATA_CONNECTION_GSM; - break; - case TelephonyManager.NETWORK_TYPE_TD_SCDMA: - bin = DATA_CONNECTION_TD_SCDMA; - break; - case TelephonyManager.NETWORK_TYPE_IWLAN: - bin = DATA_CONNECTION_IWLAN; - break; - case TelephonyManager.NETWORK_TYPE_LTE_CA: - bin = DATA_CONNECTION_LTE_CA; - break; - default: - bin = DATA_CONNECTION_OTHER; - break; + if (dataType > 0 && dataType <= TelephonyManager.MAX_NETWORK_TYPE) { + bin = dataType; + } else { + bin = DATA_CONNECTION_OTHER; } } if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData); @@ -9860,9 +9874,9 @@ public class BatteryStatsImpl extends BatteryStats { mBsi.mOnBatteryTimeBase.isRunning(), mBsi.mOnBatteryScreenOffTimeBase.isRunning(), mBsi.mConstants.PROC_STATE_CPU_TIMES_READ_DELAY_MS); - mBsi.mNumCpuTimeReads++; + mBsi.mNumSingleUidCpuTimeReads++; } else { - mBsi.mNumBatchedCpuTimeReads++; + mBsi.mNumBatchedSingleUidCpuTimeReads++; } if (mBsi.mPendingUids.indexOfKey(mUid) < 0 || ArrayUtils.contains(CRITICAL_PROC_STATES, mProcessState)) { @@ -11024,6 +11038,9 @@ public class BatteryStatsImpl extends BatteryStats { mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime = 0; mLastStepStatIdleTime = mCurStepStatIdleTime = 0; + mNumAllUidCpuTimeReads = 0; + mNumUidsRemoved = 0; + initDischarge(); clearHistoryLocked(); @@ -12009,9 +12026,11 @@ public class BatteryStatsImpl extends BatteryStats { if (!onBattery) { mKernelUidCpuTimeReader.readDelta(null); mKernelUidCpuFreqTimeReader.readDelta(null); + mNumAllUidCpuTimeReads += 2; if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) { mKernelUidCpuActiveTimeReader.readDelta(null); mKernelUidCpuClusterTimeReader.readDelta(null); + mNumAllUidCpuTimeReads += 2; } for (int cluster = mKernelCpuSpeedReaders.length - 1; cluster >= 0; --cluster) { mKernelCpuSpeedReaders[cluster].readDelta(); @@ -12029,9 +12048,11 @@ public class BatteryStatsImpl extends BatteryStats { updateClusterSpeedTimes(updatedUids, onBattery); } readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff); + mNumAllUidCpuTimeReads += 2; if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) { readKernelUidCpuActiveTimesLocked(onBattery); readKernelUidCpuClusterTimesLocked(onBattery); + mNumAllUidCpuTimeReads += 2; } } @@ -13256,11 +13277,8 @@ public class BatteryStatsImpl extends BatteryStats { public void onCleanupUserLocked(int userId) { final int firstUidForUser = UserHandle.getUid(userId, 0); final int lastUidForUser = UserHandle.getUid(userId, UserHandle.PER_USER_RANGE - 1); - mKernelUidCpuFreqTimeReader.removeUidsInRange(firstUidForUser, lastUidForUser); - mKernelUidCpuTimeReader.removeUidsInRange(firstUidForUser, lastUidForUser); - if (mKernelSingleUidTimeReader != null) { - mKernelSingleUidTimeReader.removeUidsInRange(firstUidForUser, lastUidForUser); - } + mPendingRemovedUids.add( + new UidToRemove(firstUidForUser, lastUidForUser, mClocks.elapsedRealtime())); } public void onUserRemovedLocked(int userId) { @@ -13277,12 +13295,8 @@ public class BatteryStatsImpl extends BatteryStats { * Remove the statistics object for a particular uid. */ public void removeUidStatsLocked(int uid) { - mKernelUidCpuTimeReader.removeUid(uid); - mKernelUidCpuFreqTimeReader.removeUid(uid); - if (mKernelSingleUidTimeReader != null) { - mKernelSingleUidTimeReader.removeUid(uid); - } mUidStats.remove(uid); + mPendingRemovedUids.add(new UidToRemove(uid, mClocks.elapsedRealtime())); } /** @@ -13335,24 +13349,24 @@ public class BatteryStatsImpl extends BatteryStats { = "track_cpu_times_by_proc_state"; public static final String KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME = "track_cpu_active_cluster_time"; - public static final String KEY_READ_BINARY_CPU_TIME - = "read_binary_cpu_time"; public static final String KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS = "proc_state_cpu_times_read_delay_ms"; public static final String KEY_KERNEL_UID_READERS_THROTTLE_TIME = "kernel_uid_readers_throttle_time"; + public static final String KEY_UID_REMOVE_DELAY_MS + = "uid_remove_delay_ms"; private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true; private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true; - private static final boolean DEFAULT_READ_BINARY_CPU_TIME = true; private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000; private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 10_000; + private static final long DEFAULT_UID_REMOVE_DELAY_MS = 5L * 60L * 1000L; public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE; public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME; - public boolean READ_BINARY_CPU_TIME = DEFAULT_READ_BINARY_CPU_TIME; public long PROC_STATE_CPU_TIMES_READ_DELAY_MS = DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS; public long KERNEL_UID_READERS_THROTTLE_TIME = DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME; + public long UID_REMOVE_DELAY_MS = DEFAULT_UID_REMOVE_DELAY_MS; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -13390,14 +13404,14 @@ public class BatteryStatsImpl extends BatteryStats { DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE)); TRACK_CPU_ACTIVE_CLUSTER_TIME = mParser.getBoolean( KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME, DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME); - updateReadBinaryCpuTime(READ_BINARY_CPU_TIME, - mParser.getBoolean(KEY_READ_BINARY_CPU_TIME, DEFAULT_READ_BINARY_CPU_TIME)); updateProcStateCpuTimesReadDelayMs(PROC_STATE_CPU_TIMES_READ_DELAY_MS, mParser.getLong(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS, DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS)); updateKernelUidReadersThrottleTime(KERNEL_UID_READERS_THROTTLE_TIME, mParser.getLong(KEY_KERNEL_UID_READERS_THROTTLE_TIME, DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME)); + updateUidRemoveDelay( + mParser.getLong(KEY_UID_REMOVE_DELAY_MS, DEFAULT_UID_REMOVE_DELAY_MS)); } } @@ -13407,24 +13421,17 @@ public class BatteryStatsImpl extends BatteryStats { mKernelSingleUidTimeReader.markDataAsStale(true); mExternalSync.scheduleCpuSyncDueToSettingChange(); - mNumCpuTimeReads = 0; - mNumBatchedCpuTimeReads = 0; + mNumSingleUidCpuTimeReads = 0; + mNumBatchedSingleUidCpuTimeReads = 0; mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis(); } } - private void updateReadBinaryCpuTime(boolean oldEnabled, boolean isEnabled) { - READ_BINARY_CPU_TIME = isEnabled; - if (oldEnabled != isEnabled) { - mKernelUidCpuFreqTimeReader.setReadBinary(isEnabled); - } - } - private void updateProcStateCpuTimesReadDelayMs(long oldDelayMillis, long newDelayMillis) { PROC_STATE_CPU_TIMES_READ_DELAY_MS = newDelayMillis; if (oldDelayMillis != newDelayMillis) { - mNumCpuTimeReads = 0; - mNumBatchedCpuTimeReads = 0; + mNumSingleUidCpuTimeReads = 0; + mNumBatchedSingleUidCpuTimeReads = 0; mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis(); } } @@ -13440,13 +13447,16 @@ public class BatteryStatsImpl extends BatteryStats { } } + private void updateUidRemoveDelay(long newTimeMs) { + UID_REMOVE_DELAY_MS = newTimeMs; + clearPendingRemovedUids(); + } + public void dumpLocked(PrintWriter pw) { pw.print(KEY_TRACK_CPU_TIMES_BY_PROC_STATE); pw.print("="); pw.println(TRACK_CPU_TIMES_BY_PROC_STATE); pw.print(KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME); pw.print("="); pw.println(TRACK_CPU_ACTIVE_CLUSTER_TIME); - pw.print(KEY_READ_BINARY_CPU_TIME); pw.print("="); - pw.println(READ_BINARY_CPU_TIME); pw.print(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS); pw.print("="); pw.println(PROC_STATE_CPU_TIMES_READ_DELAY_MS); pw.print(KEY_KERNEL_UID_READERS_THROTTLE_TIME); pw.print("="); @@ -13459,6 +13469,43 @@ public class BatteryStatsImpl extends BatteryStats { mConstants.dumpLocked(pw); } + @GuardedBy("this") + public void dumpCpuStatsLocked(PrintWriter pw) { + int size = mUidStats.size(); + pw.println("Per UID CPU user & system time in ms:"); + for (int i = 0; i < size; i++) { + int u = mUidStats.keyAt(i); + Uid uid = mUidStats.get(u); + pw.print(" "); pw.print(u); pw.print(": "); + pw.print(uid.getUserCpuTimeUs(STATS_SINCE_CHARGED) / 1000); pw.print(" "); + pw.println(uid.getSystemCpuTimeUs(STATS_SINCE_CHARGED) / 1000); + } + pw.println("Per UID CPU active time in ms:"); + for (int i = 0; i < size; i++) { + int u = mUidStats.keyAt(i); + Uid uid = mUidStats.get(u); + if (uid.getCpuActiveTime() > 0) { + pw.print(" "); pw.print(u); pw.print(": "); pw.println(uid.getCpuActiveTime()); + } + } + pw.println("Per UID CPU cluster time in ms:"); + for (int i = 0; i < size; i++) { + int u = mUidStats.keyAt(i); + long[] times = mUidStats.get(u).getCpuClusterTimes(); + if (times != null) { + pw.print(" "); pw.print(u); pw.print(": "); pw.println(Arrays.toString(times)); + } + } + pw.println("Per UID CPU frequency time in ms:"); + for (int i = 0; i < size; i++) { + int u = mUidStats.keyAt(i); + long[] times = mUidStats.get(u).getCpuFreqTimes(STATS_SINCE_CHARGED); + if (times != null) { + pw.print(" "); pw.print(u); pw.print(": "); pw.println(Arrays.toString(times)); + } + } + } + Parcel mPendingWrite = null; final ReentrantLock mWriteLock = new ReentrantLock(); @@ -15183,10 +15230,14 @@ public class BatteryStatsImpl extends BatteryStats { } super.dumpLocked(context, pw, flags, reqUid, histStart); pw.print("Total cpu time reads: "); - pw.println(mNumCpuTimeReads); + pw.println(mNumSingleUidCpuTimeReads); pw.print("Batched cpu time reads: "); - pw.println(mNumBatchedCpuTimeReads); + pw.println(mNumBatchedSingleUidCpuTimeReads); pw.print("Batching Duration (min): "); pw.println((mClocks.uptimeMillis() - mCpuTimeReadsTrackingStartTime) / (60 * 1000)); + pw.print("All UID cpu time reads since the later of device start or stats reset: "); + pw.println(mNumAllUidCpuTimeReads); + pw.print("UIDs removed since the later of device start or stats reset: "); + pw.println(mNumUidsRemoved); } } diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java index 12405ebce057d294ec3528be6cb4ec14525d8ead..67fbe5e76745cc245c0ae2fc81ab06a2ef127275 100644 --- a/core/java/com/android/internal/os/FuseAppLoop.java +++ b/core/java/com/android/internal/os/FuseAppLoop.java @@ -138,7 +138,7 @@ public class FuseAppLoop implements Handler.Callback { private static final int FUSE_FSYNC = 20; // Defined in FuseBuffer.h - private static final int FUSE_MAX_WRITE = 256 * 1024; + private static final int FUSE_MAX_WRITE = 128 * 1024; @Override public boolean handleMessage(Message msg) { diff --git a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java index e790e08520cbc869a1cc087643348907e6115581..bd8a67a8bd0ef8efc193c86096a6567aeaed78d7 100644 --- a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java +++ b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java @@ -24,6 +24,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.function.Consumer; /** * Reads binary proc file /proc/uid_cpupower/concurrent_active_time and reports CPU active time to @@ -54,6 +55,7 @@ public class KernelUidCpuActiveTimeReader extends private final KernelCpuProcReader mProcReader; private SparseArray mLastUidCpuActiveTimeMs = new SparseArray<>(); + private int mCores; public interface Callback extends KernelUidCpuTimeReaderBase.Callback { /** @@ -75,7 +77,60 @@ public class KernelUidCpuActiveTimeReader extends } @Override - protected void readDeltaImpl(@Nullable Callback cb) { + protected void readDeltaImpl(@Nullable Callback callback) { + readImpl((buf) -> { + int uid = buf.get(); + double activeTime = sumActiveTime(buf); + if (activeTime > 0) { + double delta = activeTime - mLastUidCpuActiveTimeMs.get(uid, 0.0); + if (delta > 0) { + mLastUidCpuActiveTimeMs.put(uid, activeTime); + if (callback != null) { + callback.onUidCpuActiveTime(uid, (long) delta); + } + } else if (delta < 0) { + Slog.e(TAG, "Negative delta from active time proc: " + delta); + } + } + }); + } + + public void readAbsolute(Callback callback) { + readImpl((buf) -> { + int uid = buf.get(); + double activeTime = sumActiveTime(buf); + if (activeTime > 0) { + callback.onUidCpuActiveTime(uid, (long) activeTime); + } + }); + } + + private double sumActiveTime(IntBuffer buffer) { + double sum = 0; + boolean corrupted = false; + for (int j = 1; j <= mCores; j++) { + int time = buffer.get(); + if (time < 0) { + // Even if error happens, we still need to continue reading. + // Buffer cannot be skipped. + Slog.e(TAG, "Negative time from active time proc: " + time); + corrupted = true; + } else { + sum += (double) time * 10 / j; // Unit is 10ms. + } + } + return corrupted ? -1 : sum; + } + + /** + * readImpl accepts a callback to process the uid entry. readDeltaImpl needs to store the last + * seen results while processing the buffer, while readAbsolute returns the absolute value read + * from the buffer without storing. So readImpl contains the common logic of the two, leaving + * the difference to a processUid function. + * + * @param processUid the callback function to process the uid entry in the buffer. + */ + private void readImpl(Consumer processUid) { synchronized (mProcReader) { final ByteBuffer bytes = mProcReader.readBytes(); if (bytes == null || bytes.remaining() <= 4) { @@ -89,6 +144,11 @@ public class KernelUidCpuActiveTimeReader extends } final IntBuffer buf = bytes.asIntBuffer(); final int cores = buf.get(); + if (mCores != 0 && cores != mCores) { + Slog.wtf(TAG, "Cpu active time wrong # cores: " + cores); + return; + } + mCores = cores; if (cores <= 0 || buf.remaining() % (cores + 1) != 0) { Slog.wtf(TAG, "Cpu active time format error: " + buf.remaining() + " / " + (cores @@ -97,25 +157,7 @@ public class KernelUidCpuActiveTimeReader extends } int numUids = buf.remaining() / (cores + 1); for (int i = 0; i < numUids; i++) { - int uid = buf.get(); - boolean corrupted = false; - double curTime = 0; - for (int j = 1; j <= cores; j++) { - int time = buf.get(); - if (time < 0) { - Slog.e(TAG, "Corrupted data from active time proc: " + time); - corrupted = true; - } else { - curTime += (double) time * 10 / j; // Unit is 10ms. - } - } - double delta = curTime - mLastUidCpuActiveTimeMs.get(uid, 0.0); - if (delta > 0 && !corrupted) { - mLastUidCpuActiveTimeMs.put(uid, curTime); - if (cb != null) { - cb.onUidCpuActiveTime(uid, (long) delta); - } - } + processUid.accept(buf); } if (DEBUG) { Slog.d(TAG, "Read uids: " + numUids); @@ -123,26 +165,11 @@ public class KernelUidCpuActiveTimeReader extends } } - public void readAbsolute(Callback cb) { - synchronized (mProcReader) { - readDelta(null); - int total = mLastUidCpuActiveTimeMs.size(); - for (int i = 0; i < total; i ++){ - int uid = mLastUidCpuActiveTimeMs.keyAt(i); - cb.onUidCpuActiveTime(uid, mLastUidCpuActiveTimeMs.get(uid).longValue()); - } - } - } - public void removeUid(int uid) { mLastUidCpuActiveTimeMs.delete(uid); } public void removeUidsInRange(int startUid, int endUid) { - if (endUid < startUid) { - Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid); - return; - } mLastUidCpuActiveTimeMs.put(startUid, null); mLastUidCpuActiveTimeMs.put(endUid, null); final int firstIndex = mLastUidCpuActiveTimeMs.indexOfKey(startUid); diff --git a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java index bf5b5203eb3f733ae88fe2e1c062b12c7b08ad83..3cbfaead477966761a5f75236c5b8524192d1c09 100644 --- a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java +++ b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java @@ -24,6 +24,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.function.Consumer; /** * Reads binary proc file /proc/uid_cpupower/concurrent_policy_time and reports CPU cluster times @@ -89,6 +90,72 @@ public class KernelUidCpuClusterTimeReader extends @Override protected void readDeltaImpl(@Nullable Callback cb) { + readImpl((buf) -> { + int uid = buf.get(); + double[] lastTimes = mLastUidPolicyTimeMs.get(uid); + if (lastTimes == null) { + lastTimes = new double[mNumClusters]; + mLastUidPolicyTimeMs.put(uid, lastTimes); + } + if (!sumClusterTime(buf, mCurTime)) { + return; + } + boolean valid = true; + boolean notify = false; + for (int i = 0; i < mNumClusters; i++) { + mDeltaTime[i] = (long) (mCurTime[i] - lastTimes[i]); + if (mDeltaTime[i] < 0) { + Slog.e(TAG, "Negative delta from cluster time proc: " + mDeltaTime[i]); + valid = false; + } + notify |= mDeltaTime[i] > 0; + } + if (notify && valid) { + System.arraycopy(mCurTime, 0, lastTimes, 0, mNumClusters); + if (cb != null) { + cb.onUidCpuPolicyTime(uid, mDeltaTime); + } + } + }); + } + + public void readAbsolute(Callback callback) { + readImpl((buf) -> { + int uid = buf.get(); + if (sumClusterTime(buf, mCurTime)) { + for (int i = 0; i < mNumClusters; i++) { + mCurTimeRounded[i] = (long) mCurTime[i]; + } + callback.onUidCpuPolicyTime(uid, mCurTimeRounded); + } + }); + } + + private boolean sumClusterTime(IntBuffer buffer, double[] clusterTime) { + boolean valid = true; + for (int i = 0; i < mNumClusters; i++) { + clusterTime[i] = 0; + for (int j = 1; j <= mNumCoresOnCluster[i]; j++) { + int time = buffer.get(); + if (time < 0) { + Slog.e(TAG, "Negative time from cluster time proc: " + time); + valid = false; + } + clusterTime[i] += (double) time * 10 / j; // Unit is 10ms. + } + } + return valid; + } + + /** + * readImpl accepts a callback to process the uid entry. readDeltaImpl needs to store the last + * seen results while processing the buffer, while readAbsolute returns the absolute value read + * from the buffer without storing. So readImpl contains the common logic of the two, leaving + * the difference to a processUid function. + * + * @param processUid the callback function to process the uid entry in the buffer. + */ + private void readImpl(Consumer processUid) { synchronized (mProcReader) { ByteBuffer bytes = mProcReader.readBytes(); if (bytes == null || bytes.remaining() <= 4) { @@ -130,7 +197,7 @@ public class KernelUidCpuClusterTimeReader extends int numUids = buf.remaining() / (mNumCores + 1); for (int i = 0; i < numUids; i++) { - processUid(buf, cb); + processUid.accept(buf); } if (DEBUG) { Slog.d(TAG, "Read uids: " + numUids); @@ -138,57 +205,6 @@ public class KernelUidCpuClusterTimeReader extends } } - public void readAbsolute(Callback cb) { - synchronized (mProcReader) { - readDelta(null); - int total = mLastUidPolicyTimeMs.size(); - for (int i = 0; i < total; i ++){ - int uid = mLastUidPolicyTimeMs.keyAt(i); - double[] lastTimes = mLastUidPolicyTimeMs.get(uid); - for (int j = 0; j < mNumClusters; j++) { - mCurTimeRounded[j] = (long) lastTimes[j]; - } - cb.onUidCpuPolicyTime(uid, mCurTimeRounded); - } - } - } - - private void processUid(IntBuffer buf, @Nullable Callback cb) { - int uid = buf.get(); - double[] lastTimes = mLastUidPolicyTimeMs.get(uid); - if (lastTimes == null) { - lastTimes = new double[mNumClusters]; - mLastUidPolicyTimeMs.put(uid, lastTimes); - } - - boolean notify = false; - boolean corrupted = false; - - for (int j = 0; j < mNumClusters; j++) { - mCurTime[j] = 0; - for (int k = 1; k <= mNumCoresOnCluster[j]; k++) { - int time = buf.get(); - if (time < 0) { - Slog.e(TAG, "Corrupted data from cluster time proc uid: " + uid); - corrupted = true; - } - mCurTime[j] += (double) time * 10 / k; // Unit is 10ms. - } - mDeltaTime[j] = (long) (mCurTime[j] - lastTimes[j]); - if (mDeltaTime[j] < 0) { - Slog.e(TAG, "Unexpected delta from cluster time proc uid: " + uid); - corrupted = true; - } - notify |= mDeltaTime[j] > 0; - } - if (notify && !corrupted) { - System.arraycopy(mCurTime, 0, lastTimes, 0, mNumClusters); - if (cb != null) { - cb.onUidCpuPolicyTime(uid, mDeltaTime); - } - } - } - // Returns if it has read valid info. private boolean readCoreInfo(IntBuffer buf, int numClusters) { int numCores = 0; @@ -214,10 +230,6 @@ public class KernelUidCpuClusterTimeReader extends } public void removeUidsInRange(int startUid, int endUid) { - if (endUid < startUid) { - Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid); - return; - } mLastUidPolicyTimeMs.put(startUid, null); mLastUidPolicyTimeMs.put(endUid, null); final int firstIndex = mLastUidPolicyTimeMs.indexOfKey(startUid); diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java index f65074f65d874349a01c61f3eb407ee62afaa866..5b46d0f29c20a4870a86c036bddd956a5a6a2865 100644 --- a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java +++ b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java @@ -21,11 +21,9 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.StrictMode; -import android.os.SystemClock; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; -import android.util.TimeUtils; import com.android.internal.annotations.VisibleForTesting; @@ -34,6 +32,7 @@ import java.io.FileReader; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.function.Consumer; /** * Reads /proc/uid_time_in_state which has the format: @@ -75,9 +74,6 @@ public class KernelUidCpuFreqTimeReader extends private long[] mCurTimes; // Reuse to prevent GC. private long[] mDeltaTimes; // Reuse to prevent GC. private int mCpuFreqsCount; - private long mLastTimeReadMs = Long.MIN_VALUE; - private long mNowTimeMs; - private boolean mReadBinary = true; private final KernelCpuProcReader mProcReader; private SparseArray mLastUidCpuFreqTimeMs = new SparseArray<>(); @@ -140,40 +136,99 @@ public class KernelUidCpuFreqTimeReader extends if (line == null) { return null; } - return readCpuFreqs(line, powerProfile); - } + final String[] freqStr = line.split(" "); + // First item would be "uid: " which needs to be ignored. + mCpuFreqsCount = freqStr.length - 1; + mCpuFreqs = new long[mCpuFreqsCount]; + mCurTimes = new long[mCpuFreqsCount]; + mDeltaTimes = new long[mCpuFreqsCount]; + for (int i = 0; i < mCpuFreqsCount; ++i) { + mCpuFreqs[i] = Long.parseLong(freqStr[i + 1], 10); + } - public void setReadBinary(boolean readBinary) { - mReadBinary = readBinary; + // Check if the freqs in the proc file correspond to per-cluster freqs. + final IntArray numClusterFreqs = extractClusterInfoFromProcFileFreqs(); + final int numClusters = powerProfile.getNumCpuClusters(); + if (numClusterFreqs.size() == numClusters) { + mPerClusterTimesAvailable = true; + for (int i = 0; i < numClusters; ++i) { + if (numClusterFreqs.get(i) != powerProfile.getNumSpeedStepsInCpuCluster(i)) { + mPerClusterTimesAvailable = false; + break; + } + } + } else { + mPerClusterTimesAvailable = false; + } + Slog.i(TAG, "mPerClusterTimesAvailable=" + mPerClusterTimesAvailable); + return mCpuFreqs; } @Override - protected void readDeltaImpl(@Nullable Callback callback) { + @VisibleForTesting + public void readDeltaImpl(@Nullable Callback callback) { if (mCpuFreqs == null) { return; } - if (mReadBinary) { - readDeltaBinary(callback); - } else { - readDeltaString(callback); - } + readImpl((buf) -> { + int uid = buf.get(); + long[] lastTimes = mLastUidCpuFreqTimeMs.get(uid); + if (lastTimes == null) { + lastTimes = new long[mCpuFreqsCount]; + mLastUidCpuFreqTimeMs.put(uid, lastTimes); + } + if (!getFreqTimeForUid(buf, mCurTimes)) { + return; + } + boolean notify = false; + boolean valid = true; + for (int i = 0; i < mCpuFreqsCount; i++) { + mDeltaTimes[i] = mCurTimes[i] - lastTimes[i]; + if (mDeltaTimes[i] < 0) { + Slog.e(TAG, "Negative delta from freq time proc: " + mDeltaTimes[i]); + valid = false; + } + notify |= mDeltaTimes[i] > 0; + } + if (notify && valid) { + System.arraycopy(mCurTimes, 0, lastTimes, 0, mCpuFreqsCount); + if (callback != null) { + callback.onUidCpuFreqTime(uid, mDeltaTimes); + } + } + }); } - private void readDeltaString(@Nullable Callback callback) { - mNowTimeMs = SystemClock.elapsedRealtime(); - final int oldMask = StrictMode.allowThreadDiskReadsMask(); - try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { - readDelta(reader, callback); - } catch (IOException e) { - Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e); - } finally { - StrictMode.setThreadPolicyMask(oldMask); + public void readAbsolute(Callback callback) { + readImpl((buf) -> { + int uid = buf.get(); + if (getFreqTimeForUid(buf, mCurTimes)) { + callback.onUidCpuFreqTime(uid, mCurTimes); + } + }); + } + + private boolean getFreqTimeForUid(IntBuffer buffer, long[] freqTime) { + boolean valid = true; + for (int i = 0; i < mCpuFreqsCount; i++) { + freqTime[i] = (long) buffer.get() * 10; // Unit is 10ms. + if (freqTime[i] < 0) { + Slog.e(TAG, "Negative time from freq time proc: " + freqTime[i]); + valid = false; + } } - mLastTimeReadMs = mNowTimeMs; + return valid; } - @VisibleForTesting - public void readDeltaBinary(@Nullable Callback callback) { + /** + * readImpl accepts a callback to process the uid entry. readDeltaImpl needs to store the last + * seen results while processing the buffer, while readAbsolute returns the absolute value read + * from the buffer without storing. So readImpl contains the common logic of the two, leaving + * the difference to a processUid function. + * + * @param processUid the callback function to process the uid entry in the buffer. + */ + private void readImpl(Consumer processUid) { synchronized (mProcReader) { ByteBuffer bytes = mProcReader.readBytes(); if (bytes == null || bytes.remaining() <= 4) { @@ -181,7 +236,7 @@ public class KernelUidCpuFreqTimeReader extends return; } if ((bytes.remaining() & 3) != 0) { - Slog.wtf(TAG, "Cannot parse cluster time proc bytes to int: " + bytes.remaining()); + Slog.wtf(TAG, "Cannot parse freq time proc bytes to int: " + bytes.remaining()); return; } IntBuffer buf = bytes.asIntBuffer(); @@ -196,43 +251,10 @@ public class KernelUidCpuFreqTimeReader extends } int numUids = buf.remaining() / (freqs + 1); for (int i = 0; i < numUids; i++) { - int uid = buf.get(); - long[] lastTimes = mLastUidCpuFreqTimeMs.get(uid); - if (lastTimes == null) { - lastTimes = new long[mCpuFreqsCount]; - mLastUidCpuFreqTimeMs.put(uid, lastTimes); - } - boolean notify = false; - boolean corrupted = false; - for (int j = 0; j < freqs; j++) { - mCurTimes[j] = (long) buf.get() * 10; // Unit is 10ms. - mDeltaTimes[j] = mCurTimes[j] - lastTimes[j]; - if (mCurTimes[j] < 0 || mDeltaTimes[j] < 0) { - Slog.e(TAG, "Unexpected data from freq time proc: " + mCurTimes[j]); - corrupted = true; - } - notify |= mDeltaTimes[j] > 0; - } - if (notify && !corrupted) { - System.arraycopy(mCurTimes, 0, lastTimes, 0, freqs); - if (callback != null) { - callback.onUidCpuFreqTime(uid, mDeltaTimes); - } - } + processUid.accept(buf); } if (DEBUG) { - Slog.d(TAG, "Read uids: " + numUids); - } - } - } - - public void readAbsolute(Callback cb) { - synchronized (mProcReader) { - readDelta(null); - int total = mLastUidCpuFreqTimeMs.size(); - for (int i = 0; i < total; i ++){ - int uid = mLastUidCpuFreqTimeMs.keyAt(i); - cb.onUidCpuFreqTime(uid, mLastUidCpuFreqTimeMs.get(uid)); + Slog.d(TAG, "Read uids: #" + numUids); } } } @@ -242,9 +264,6 @@ public class KernelUidCpuFreqTimeReader extends } public void removeUidsInRange(int startUid, int endUid) { - if (endUid < startUid) { - return; - } mLastUidCpuFreqTimeMs.put(startUid, null); mLastUidCpuFreqTimeMs.put(endUid, null); final int firstIndex = mLastUidCpuFreqTimeMs.indexOfKey(startUid); @@ -252,97 +271,6 @@ public class KernelUidCpuFreqTimeReader extends mLastUidCpuFreqTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1); } - @VisibleForTesting - public void readDelta(BufferedReader reader, @Nullable Callback callback) throws IOException { - String line = reader.readLine(); - if (line == null) { - return; - } - while ((line = reader.readLine()) != null) { - final int index = line.indexOf(' '); - final int uid = Integer.parseInt(line.substring(0, index - 1), 10); - readTimesForUid(uid, line.substring(index + 1, line.length()), callback); - } - } - - private void readTimesForUid(int uid, String line, Callback callback) { - long[] uidTimeMs = mLastUidCpuFreqTimeMs.get(uid); - if (uidTimeMs == null) { - uidTimeMs = new long[mCpuFreqsCount]; - mLastUidCpuFreqTimeMs.put(uid, uidTimeMs); - } - final String[] timesStr = line.split(" "); - final int size = timesStr.length; - if (size != uidTimeMs.length) { - Slog.e(TAG, "No. of readings don't match cpu freqs, readings: " + size - + " cpuFreqsCount: " + uidTimeMs.length); - return; - } - final long[] deltaUidTimeMs = new long[size]; - final long[] curUidTimeMs = new long[size]; - boolean notify = false; - for (int i = 0; i < size; ++i) { - // Times read will be in units of 10ms - final long totalTimeMs = Long.parseLong(timesStr[i], 10) * 10; - deltaUidTimeMs[i] = totalTimeMs - uidTimeMs[i]; - // If there is malformed data for any uid, then we just log about it and ignore - // the data for that uid. - if (deltaUidTimeMs[i] < 0 || totalTimeMs < 0) { - if (DEBUG) { - final StringBuilder sb = new StringBuilder("Malformed cpu freq data for UID=") - .append(uid).append("\n"); - sb.append("data=").append("(").append(uidTimeMs[i]).append(",") - .append(totalTimeMs).append(")").append("\n"); - sb.append("times=").append("("); - TimeUtils.formatDuration(mLastTimeReadMs, sb); - sb.append(","); - TimeUtils.formatDuration(mNowTimeMs, sb); - sb.append(")"); - Slog.e(TAG, sb.toString()); - } - return; - } - curUidTimeMs[i] = totalTimeMs; - notify = notify || (deltaUidTimeMs[i] > 0); - } - if (notify) { - System.arraycopy(curUidTimeMs, 0, uidTimeMs, 0, size); - if (callback != null) { - callback.onUidCpuFreqTime(uid, deltaUidTimeMs); - } - } - } - - private long[] readCpuFreqs(String line, PowerProfile powerProfile) { - final String[] freqStr = line.split(" "); - // First item would be "uid: " which needs to be ignored. - mCpuFreqsCount = freqStr.length - 1; - mCpuFreqs = new long[mCpuFreqsCount]; - mCurTimes = new long[mCpuFreqsCount]; - mDeltaTimes = new long[mCpuFreqsCount]; - for (int i = 0; i < mCpuFreqsCount; ++i) { - mCpuFreqs[i] = Long.parseLong(freqStr[i + 1], 10); - } - - // Check if the freqs in the proc file correspond to per-cluster freqs. - final IntArray numClusterFreqs = extractClusterInfoFromProcFileFreqs(); - final int numClusters = powerProfile.getNumCpuClusters(); - if (numClusterFreqs.size() == numClusters) { - mPerClusterTimesAvailable = true; - for (int i = 0; i < numClusters; ++i) { - if (numClusterFreqs.get(i) != powerProfile.getNumSpeedStepsInCpuCluster(i)) { - mPerClusterTimesAvailable = false; - break; - } - } - } else { - mPerClusterTimesAvailable = false; - } - Slog.i(TAG, "mPerClusterTimesAvailable=" + mPerClusterTimesAvailable); - - return mCpuFreqs; - } - /** * Extracts no. of cpu clusters and no. of freqs in each of these clusters from the freqs * read from the proc file. diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java index 749d00c136ec04c3760de54322a934611f07e65d..5b6b619ed7d287911674e14329ad285100a02eee 100644 --- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java +++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java @@ -325,14 +325,14 @@ public class PipSnapAlgorithm { * {@param stackBounds}. */ public void getMovementBounds(Rect stackBounds, Rect insetBounds, Rect movementBoundsOut, - int imeHeight) { + int bottomOffset) { // Adjust the right/bottom to ensure the stack bounds never goes offscreen movementBoundsOut.set(insetBounds); movementBoundsOut.right = Math.max(insetBounds.left, insetBounds.right - stackBounds.width()); movementBoundsOut.bottom = Math.max(insetBounds.top, insetBounds.bottom - stackBounds.height()); - movementBoundsOut.bottom -= imeHeight; + movementBoundsOut.bottom -= bottomOffset; } /** diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java index 82ac2412e4b2e2f12e5cb34fab1ce8168fbe6112..d53090b4678c0b2f85088bad52817bd96fc13d30 100644 --- a/core/java/com/android/internal/util/FunctionalUtils.java +++ b/core/java/com/android/internal/util/FunctionalUtils.java @@ -17,6 +17,7 @@ package com.android.internal.util; import android.os.RemoteException; +import android.util.ExceptionUtils; import java.util.function.Consumer; import java.util.function.Supplier; @@ -36,12 +37,26 @@ public class FunctionalUtils { } /** - * + * Wraps a given {@code action} into one that ignores any {@link RemoteException}s */ public static Consumer ignoreRemoteException(RemoteExceptionIgnoringConsumer action) { return action; } + /** + * Wraps the given {@link ThrowingRunnable} into one that handles any exceptions using the + * provided {@code handler} + */ + public static Runnable handleExceptions(ThrowingRunnable r, Consumer handler) { + return () -> { + try { + r.run(); + } catch (Throwable t) { + handler.accept(t); + } + }; + } + /** * An equivalent of {@link Runnable} that allows throwing checked exceptions * @@ -49,8 +64,18 @@ public class FunctionalUtils { * to be handled within it */ @FunctionalInterface - public interface ThrowingRunnable { + @SuppressWarnings("FunctionalInterfaceMethodChanged") + public interface ThrowingRunnable extends Runnable { void runOrThrow() throws Exception; + + @Override + default void run() { + try { + runOrThrow(); + } catch (Exception ex) { + throw ExceptionUtils.propagate(ex); + } + } } /** @@ -80,7 +105,7 @@ public class FunctionalUtils { try { acceptOrThrow(t); } catch (Exception ex) { - throw new RuntimeException(ex); + throw ExceptionUtils.propagate(ex); } } } diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index 72cd24888dcc83d50588c46263676f6ac83b5f52..6c3a58ce3908fdb1cd613380cdad3266ae21005e 100644 --- a/core/java/com/android/internal/util/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -147,8 +147,17 @@ public class LatencyTracker { } mStartRtc.delete(action); Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, NAMES[action], 0); - long duration = endRtc - startRtc; + logAction(action, (int)(endRtc - startRtc)); + } + + /** + * Logs an action that has started and ended. This needs to be called from the main thread. + * + * @param action The action to end. One of the ACTION_* values. + * @param duration The duration of the action in ms. + */ + public static void logAction(int action, int duration) { Log.i(TAG, "action=" + action + " latency=" + duration); - EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, (int) duration); + EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration); } } diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index 9d012de33089e9dabf6167dfb20263585286807f..0c5ea6327dff1f56d4796bba5a2816315eefdfd8 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/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index e3b1c01fd12b2a9866c19a39fb23a294f5cc0de5..35aae15a809c4b2658c932720477f002fa2ffecc 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -1784,7 +1784,8 @@ public final class FloatingToolbar { private static Context applyDefaultTheme(Context originalContext) { TypedArray a = originalContext.obtainStyledAttributes(new int[]{R.attr.isLightTheme}); boolean isLightTheme = a.getBoolean(0, true); - int themeId = isLightTheme ? R.style.Theme_Material_Light : R.style.Theme_Material; + int themeId + = isLightTheme ? R.style.Theme_DeviceDefault_Light : R.style.Theme_DeviceDefault; a.recycle(); return new ContextThemeWrapper(originalContext, themeId); } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 5a06f7fe19906b76d617c27060bc179518419566..25e1589db74e079b326e3ccfc826b27d77cb3306 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -54,13 +54,6 @@ interface ILockSettings { void userPresent(int userId); int getStrongAuthForUser(int userId); - long addEscrowToken(in byte[] token, int userId); - boolean removeEscrowToken(long handle, int userId); - boolean isEscrowTokenActive(long handle, int userId); - boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, - in byte[] token, int requestedQuality, int userId); - void unlockUserWithToken(long tokenHandle, in byte[] token, int userId); - // Keystore RecoveryController methods. // {@code ServiceSpecificException} may be thrown to signal an error, which caller can // convert to {@code RecoveryManagerException}. diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 7eb2f38f52873b44db9cc63a2fb0c25372b2a6f1..fde7e961b843bef1bc5354b2ba0966dda343391f 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -45,6 +45,7 @@ import android.util.SparseIntArray; import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; import com.google.android.collect.Lists; import libcore.util.HexEncoding; @@ -1454,6 +1455,11 @@ public class LockPatternUtils { return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_FINGERPRINT) == 0; } + public boolean isUserInLockdown(int userId) { + return getStrongAuthForUser(userId) + == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; + } + private ICheckCredentialProgressCallback wrapCallback( final CheckCredentialProgressCallback callback) { if (callback == null) { @@ -1473,6 +1479,13 @@ public class LockPatternUtils { } } + private LockSettingsInternal getLockSettingsInternal() { + LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class); + if (service == null) { + throw new SecurityException("Only available to system server itself"); + } + return service; + } /** * Create an escrow token for the current user, which can later be used to unlock FBE * or change user password. @@ -1481,44 +1494,41 @@ public class LockPatternUtils { * confirm credential operation in order to activate the token for future use. If the user * has no secure lockscreen, then the token is activated immediately. * + *

    This method is only available to code running in the system server process itself. + * * @return a unique 64-bit token handle which is needed to refer to this token later. */ public long addEscrowToken(byte[] token, int userId) { - try { - return getLockSettings().addEscrowToken(token, userId); - } catch (RemoteException re) { - return 0L; - } + return getLockSettingsInternal().addEscrowToken(token, userId); } /** * Remove an escrow token. + * + *

    This method is only available to code running in the system server process itself. + * * @return true if the given handle refers to a valid token previously returned from * {@link #addEscrowToken}, whether it's active or not. return false otherwise. */ public boolean removeEscrowToken(long handle, int userId) { - try { - return getLockSettings().removeEscrowToken(handle, userId); - } catch (RemoteException re) { - return false; - } + return getLockSettingsInternal().removeEscrowToken(handle, userId); } /** * Check if the given escrow token is active or not. Only active token can be used to call * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken} + * + *

    This method is only available to code running in the system server process itself. */ public boolean isEscrowTokenActive(long handle, int userId) { - try { - return getLockSettings().isEscrowTokenActive(handle, userId); - } catch (RemoteException re) { - return false; - } + return getLockSettingsInternal().isEscrowTokenActive(handle, userId); } /** * Change a user's lock credential with a pre-configured escrow token. * + *

    This method is only available to code running in the system server process itself. + * * @param credential The new credential to be set * @param type Credential type: password / pattern / none. * @param requestedQuality the requested password quality by DevicePolicyManager. @@ -1530,55 +1540,55 @@ public class LockPatternUtils { */ public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality, long tokenHandle, byte[] token, int userId) { - try { - if (type != CREDENTIAL_TYPE_NONE) { - if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) { - throw new IllegalArgumentException("password must not be null and at least " - + "of length " + MIN_LOCK_PASSWORD_SIZE); - } - final int quality = computePasswordQuality(type, credential, requestedQuality); - if (!getLockSettings().setLockCredentialWithToken(credential, type, tokenHandle, - token, quality, userId)) { - return false; - } - setLong(PASSWORD_TYPE_KEY, quality, userId); + LockSettingsInternal localService = getLockSettingsInternal(); + if (type != CREDENTIAL_TYPE_NONE) { + if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) { + throw new IllegalArgumentException("password must not be null and at least " + + "of length " + MIN_LOCK_PASSWORD_SIZE); + } + final int quality = computePasswordQuality(type, credential, requestedQuality); + if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, + token, quality, userId)) { + return false; + } + setLong(PASSWORD_TYPE_KEY, quality, userId); - updateEncryptionPasswordIfNeeded(credential, quality, userId); - updatePasswordHistory(credential, userId); - } else { - if (!TextUtils.isEmpty(credential)) { - throw new IllegalArgumentException("password must be emtpy for NONE type"); - } - if (!getLockSettings().setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, - tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, - userId)) { - return false; - } - setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, - userId); + updateEncryptionPasswordIfNeeded(credential, quality, userId); + updatePasswordHistory(credential, userId); + } else { + if (!TextUtils.isEmpty(credential)) { + throw new IllegalArgumentException("password must be emtpy for NONE type"); + } + if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, + tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, + userId)) { + return false; + } + setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, + userId); - if (userId == UserHandle.USER_SYSTEM) { - // Set the encryption password to default. - updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); - setCredentialRequiredToDecrypt(false); - } + if (userId == UserHandle.USER_SYSTEM) { + // Set the encryption password to default. + updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null); + setCredentialRequiredToDecrypt(false); } - onAfterChangingPassword(userId); - return true; - } catch (RemoteException re) { - Log.e(TAG, "Unable to save lock password ", re); - re.rethrowFromSystemServer(); } - return false; + onAfterChangingPassword(userId); + return true; } - public void unlockUserWithToken(long tokenHandle, byte[] token, int userId) { - try { - getLockSettings().unlockUserWithToken(tokenHandle, token, userId); - } catch (RemoteException re) { - Log.e(TAG, "Unable to unlock user with token", re); - re.rethrowFromSystemServer(); - } + /** + * Unlock the specified user by an pre-activated escrow token. This should have the same effect + * on device encryption as the user entering his lockscreen credentials for the first time after + * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore + * + *

    This method is only available to code running in the system server process itself. + * + * @return {@code true} if the supplied token is valid and unlock succeeds, + * {@code false} otherwise. + */ + public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) { + return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId); } diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java new file mode 100644 index 0000000000000000000000000000000000000000..9de9ef7f2aeaf2484e8a06cb6bb0be3729d024cc --- /dev/null +++ b/core/java/com/android/internal/widget/LockSettingsInternal.java @@ -0,0 +1,56 @@ +/* + * 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 com.android.internal.widget; + + +/** + * LockSettingsService local system service interface. + * + * @hide Only for use within the system server. + */ +public abstract class LockSettingsInternal { + + /** + * Create an escrow token for the current user, which can later be used to unlock FBE + * or change user password. + * + * After adding, if the user currently has lockscreen password, he will need to perform a + * confirm credential operation in order to activate the token for future use. If the user + * has no secure lockscreen, then the token is activated immediately. + * + * @return a unique 64-bit token handle which is needed to refer to this token later. + */ + public abstract long addEscrowToken(byte[] token, int userId); + + /** + * Remove an escrow token. + * @return true if the given handle refers to a valid token previously returned from + * {@link #addEscrowToken}, whether it's active or not. return false otherwise. + */ + public abstract boolean removeEscrowToken(long handle, int userId); + + /** + * Check if the given escrow token is active or not. Only active token can be used to call + * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken} + */ + public abstract boolean isEscrowTokenActive(long handle, int userId); + + public abstract boolean setLockCredentialWithToken(String credential, int type, + long tokenHandle, byte[] token, int requestedQuality, int userId); + + public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId); +} diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 8b1de2fb886e16222bb6f2fd2ee367513b0e97aa..c71e505c6790ef0a00f4e12afc43c56585e2902a 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -22,6 +22,7 @@ import android.app.ActivityManager; import android.content.ComponentName; import android.content.pm.FeatureInfo; import android.content.pm.PackageManager; +import android.os.Build; import android.os.Environment; import android.os.Process; import android.os.storage.StorageManager; @@ -276,16 +277,20 @@ public class SystemConfig { readPermissions(Environment.buildPath( Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL); - // Allow Vendor to customize system configs around libs, features, permissions and apps - int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS | - ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS; + // Vendors are only allowed to customze libs, features and privapp permissions + int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS; + if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) { + // For backward compatibility + vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS); + } readPermissions(Environment.buildPath( Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag); readPermissions(Environment.buildPath( Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag); - // Allow ODM to customize system configs around libs, features and apps - int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS; + // Allow ODM to customize system configs as much as Vendor, because /odm is another + // vendor partition other than /vendor. + int odmPermissionFlag = vendorPermissionFlag; readPermissions(Environment.buildPath( Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag); readPermissions(Environment.buildPath( @@ -631,7 +636,9 @@ public class SystemConfig { // granting permissions to priv apps in the system partition and vice // versa. boolean vendor = permFile.toPath().startsWith( - Environment.getVendorDirectory().toPath()); + Environment.getVendorDirectory().toPath()) + || permFile.toPath().startsWith( + Environment.getOdmDirectory().toPath()); boolean product = permFile.toPath().startsWith( Environment.getProductDirectory().toPath()); if (vendor) { @@ -656,6 +663,8 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } else { + Slog.w(TAG, "Tag " + name + " is unknown or not allowed in " + + permFile.getParent()); XmlUtils.skipCurrentTag(parser); continue; } diff --git a/core/java/com/android/server/net/BaseNetdEventCallback.java b/core/java/com/android/server/net/BaseNetdEventCallback.java index 3d3a3d07b216320255730312a9101afce23b2246..fdba2f3dc9e61ad5f0b7d37ad3cc71218852cf45 100644 --- a/core/java/com/android/server/net/BaseNetdEventCallback.java +++ b/core/java/com/android/server/net/BaseNetdEventCallback.java @@ -31,6 +31,12 @@ public class BaseNetdEventCallback extends INetdEventCallback.Stub { // default no-op } + @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/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 5498a931718dcb6e7d01d38f2430a063b445035e..5a74a2473b320eddde94a8bb745e4c806375e443 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -921,6 +921,28 @@ static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, SkBitmap skbitmap; bitmap->getSkBitmap(&skbitmap); + if (skbitmap.colorType() == kRGBA_F16_SkColorType) { + // Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace + // for wide gamuts. + auto cs = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, + SkColorSpace::kDCIP3_D65_Gamut); + auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType) + .makeColorSpace(std::move(cs)); + SkBitmap p3; + if (!p3.tryAllocPixels(info)) { + return JNI_FALSE; + } + auto xform = SkColorSpaceXform::New(skbitmap.colorSpace(), info.colorSpace()); + if (!xform) { + return JNI_FALSE; + } + if (!xform->apply(SkColorSpaceXform::kRGBA_8888_ColorFormat, p3.getPixels(), + SkColorSpaceXform::kRGBA_F16_ColorFormat, skbitmap.getPixels(), + info.width() * info.height(), kUnpremul_SkAlphaType)) { + return JNI_FALSE; + } + skbitmap = p3; + } return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE; } @@ -1247,6 +1269,15 @@ static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) { return GraphicsJNI::isColorSpaceSRGB(colorSpace); } +static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) { + LocalScopedBitmap bitmapHolder(bitmapHandle); + if (!bitmapHolder.valid()) return JNI_FALSE; + + SkColorSpace* colorSpace = bitmapHolder->info().colorSpace(); + sk_sp srgbLinear = SkColorSpace::MakeSRGBLinear(); + return colorSpace == srgbLinear.get() ? JNI_TRUE : JNI_FALSE; +} + static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, jfloatArray xyzArray, jfloatArray paramsArray) { @@ -1592,6 +1623,7 @@ static const JNINativeMethod gBitmapMethods[] = { (void*) Bitmap_createGraphicBufferHandle }, { "nativeGetColorSpace", "(J[F[F)Z", (void*)Bitmap_getColorSpace }, { "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB }, + { "nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear}, { "nativeCopyColorSpace", "(JJ)V", (void*)Bitmap_copyColorSpace }, }; diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index 3b081eff110a6c9b1d496f94bb6cf03207624b52..f831c051182ec000b9b121e3f9ea6b1fa19d9415 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -155,12 +155,6 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in env->SetObjectField(options, gOptions_outColorSpaceFieldID, 0); } - SkBitmapRegionDecoder* brd = reinterpret_cast(brdHandle); - - SkColorType decodeColorType = brd->computeOutputColorType(colorType); - sk_sp decodeColorSpace = brd->computeOutputColorSpace( - decodeColorType, colorSpace); - // Recycle a bitmap if possible. android::Bitmap* recycledBitmap = nullptr; size_t recycledBytes = 0; @@ -172,6 +166,9 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in recycledBytes = bitmap::getBitmapAllocationByteCount(env, javaBitmap); } + SkBitmapRegionDecoder* brd = reinterpret_cast(brdHandle); + SkColorType decodeColorType = brd->computeOutputColorType(colorType); + // Set up the pixel allocator SkBRDAllocator* allocator = nullptr; RecyclingClippingPixelAllocator recycleAlloc(recycledBitmap, recycledBytes); @@ -184,6 +181,9 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in allocator = &heapAlloc; } + sk_sp decodeColorSpace = brd->computeOutputColorSpace( + decodeColorType, colorSpace); + // Decode the region. SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight); SkBitmap bitmap; diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 2c05d0b976fc8b0b158b029a38d9164fb7ea99e3..bd14d45325a7a26c5a76ed3f6ecb77a3d74b49f4 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(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(bidiFlags), typeface, text, 0, count, count, nullptr, - 0); + static_cast(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(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(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/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp index d20c7ef2ec76e426a2a83cd7b023142d062708fd..32ac30fdabb05027d63ea088388419d499e3ec9a 100644 --- a/core/jni/android/graphics/pdf/PdfRenderer.cpp +++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp @@ -92,20 +92,7 @@ static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong renderFlags |= FPDF_PRINTING; } - // PDF's coordinate system origin is left-bottom while in graphics it - // is the top-left. So, translate the PDF coordinates to ours. - SkMatrix reflectOnX = SkMatrix::MakeScale(1, -1); - SkMatrix moveUp = SkMatrix::MakeTrans(0, FPDF_GetPageHeight(page)); - SkMatrix coordinateChange = SkMatrix::Concat(moveUp, reflectOnX); - - // Apply the transformation - SkMatrix matrix; - if (transformPtr == 0) { - matrix = coordinateChange; - } else { - matrix = SkMatrix::Concat(*reinterpret_cast(transformPtr), coordinateChange); - } - + SkMatrix matrix = *reinterpret_cast(transformPtr); SkScalar transformValues[6]; if (!matrix.asAffine(transformValues)) { jniThrowException(env, "java/lang/IllegalArgumentException", diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index 06de5daab7d241069e145145be69fa22f8bc012e..0017f6cd8a417b5e49c2d7e10b3e17c3a4027d00 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(bidiFlags), *paint, typeface, nullptr, 0); + static_cast(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(bidiFlags), *paint, typeface, nullptr, 0); + static_cast(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(paintHandle); minikin::MeasuredText* mt = reinterpret_cast(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/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp index a94cac0f18f537b92ba675e67f542b252e37c48d..9ec7517754d9a55b3bc6a9820382a7f509f3f732 100644 --- a/core/jni/android_os_SystemProperties.cpp +++ b/core/jni/android_os_SystemProperties.cpp @@ -124,6 +124,12 @@ void do_report_sysprop_change() { if (sVM->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0) { //ALOGI("Java SystemProperties: calling %p", sCallChangeCallbacks); env->CallStaticVoidMethod(sClazz, sCallChangeCallbacks); + // There should not be any exceptions. But we must guarantee + // there are none on return. + if (env->ExceptionCheck()) { + env->ExceptionClear(); + LOG(ERROR) << "Exception pending after sysprop_change!"; + } } } } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 8ca506254f74002ab189867a3d2eaed6ff2befb3..04cb08f51efa8c673ed6cfa72474c4a14fad4f2c 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -36,8 +36,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -115,9 +116,13 @@ static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj, ScopedUtfChars name(env, nameStr); sp client(android_view_SurfaceSession_getClient(env, sessionObj)); SurfaceControl *parent = reinterpret_cast(parentObject); - sp surface = client->createSurface( - String8(name.c_str()), w, h, format, flags, parent, windowType, ownerUid); - if (surface == NULL) { + sp surface; + status_t err = client->createSurfaceChecked( + String8(name.c_str()), w, h, format, &surface, flags, parent, windowType, ownerUid); + if (err == NAME_NOT_FOUND) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return 0; + } else if (err != NO_ERROR) { jniThrowException(env, OutOfResourcesException, NULL); return 0; } @@ -290,7 +295,7 @@ static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandl } sp buffer; - status_t res = ScreenshotClient::captureLayers(layerHandle, sourceCrop, frameScale, &buffer); + status_t res = ScreenshotClient::captureChildLayers(layerHandle, sourceCrop, frameScale, &buffer); if (res != NO_ERROR) { return NULL; } @@ -593,7 +598,7 @@ static jboolean nativeSetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenOb static jintArray nativeGetDisplayColorModes(JNIEnv* env, jclass, jobject tokenObj) { sp token(ibinderForJavaObject(env, tokenObj)); if (token == NULL) return NULL; - Vector colorModes; + Vector colorModes; if (SurfaceComposerClient::getDisplayColorModes(token, &colorModes) != NO_ERROR || colorModes.isEmpty()) { return NULL; @@ -623,7 +628,7 @@ static jboolean nativeSetActiveColorMode(JNIEnv* env, jclass, sp token(ibinderForJavaObject(env, tokenObj)); if (token == NULL) return JNI_FALSE; status_t err = SurfaceComposerClient::setActiveColorMode(token, - static_cast(colorMode)); + static_cast(colorMode)); return err == NO_ERROR ? JNI_TRUE : JNI_FALSE; } diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index b614c891b9f830a95b3951ba68385eb50b212cc2..451f278313b5e0ee1068857781be52e38f117160 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -988,6 +988,11 @@ static void android_view_ThreadedRenderer_setDebuggingEnabled(JNIEnv*, jclass, j Properties::debuggingEnabled = enable; } +static void android_view_ThreadedRenderer_setIsolatedProcess(JNIEnv*, jclass, jboolean isolated) { + Properties::isolatedProcess = isolated; +} + + // ---------------------------------------------------------------------------- // FrameMetricsObserver // ---------------------------------------------------------------------------- @@ -1097,6 +1102,7 @@ static const JNINativeMethod gMethods[] = { { "nHackySetRTAnimationsEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled }, { "nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled }, + { "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess }, }; static JavaVM* mJvm = nullptr; diff --git a/core/jni/com_android_internal_os_FuseAppLoop.cpp b/core/jni/com_android_internal_os_FuseAppLoop.cpp index 8837df5b2da7ba157225dac7cc87f996a8cbda55..fdc088eee6b3861dd55e09ec0c05816394568856 100644 --- a/core/jni/com_android_internal_os_FuseAppLoop.cpp +++ b/core/jni/com_android_internal_os_FuseAppLoop.cpp @@ -166,8 +166,8 @@ void com_android_internal_os_FuseAppLoop_replyWrite( void com_android_internal_os_FuseAppLoop_replyRead( JNIEnv* env, jobject self, jlong ptr, jlong unique, jint size, jbyteArray data) { ScopedByteArrayRO array(env, data); - CHECK(size >= 0); - CHECK(static_cast(size) < array.size()); + CHECK_GE(size, 0); + CHECK_LE(static_cast(size), array.size()); if (!reinterpret_cast(ptr)->ReplyRead(unique, size, array.get())) { reinterpret_cast(ptr)->Break(); } diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index d05be2ca787ba185cb2d73c7d75e23eeb293ff99..7c8a52d1432bf92aff8b25b0597d513add7d743d 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(&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 javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i)); ScopedIntArrayRO javaRlimit(env, reinterpret_cast(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* fds) { + std::vector* 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 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 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 2e6058268115f399b017e28f42a46586cca8baa5..c5904e0e9e5ef3d14d158b99ce83f5d684025206 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& fds_to_ignore) { +FileDescriptorTable* FileDescriptorTable::Create(const std::vector& 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& 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& 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& fds_to_ignore) { +bool FileDescriptorTable::Restat(const std::vector& fds_to_ignore, std::string* error_msg) { std::set 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& 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::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& open_fds) { +bool FileDescriptorTable::RestatInternal(std::set& 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& 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::iterator it = open_fd_map_.begin(); while (it != open_fd_map_.end()) { std::set::const_iterator element = open_fds.find(it->first); @@ -475,7 +554,7 @@ bool FileDescriptorTable::RestatInternal(std::set& 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& open_fds) { std::set::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 a39e387fde6cbfd94acaf4dc5fd6283c6656dd49..a3570d7ed1fbabbd25d13c17623b26ea4ba915d0 100644 --- a/core/jni/fd_utils.h +++ b/core/jni/fd_utils.h @@ -28,6 +28,8 @@ #include +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& fds_to_ignore); + static FileDescriptorTable* Create(const std::vector& fds_to_ignore, + std::string* error_msg); - bool Restat(const std::vector& fds_to_ignore); + bool Restat(const std::vector& 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& map); - bool RestatInternal(std::set& open_fds); + bool RestatInternal(std::set& open_fds, std::string* error_msg); static int ParseFd(dirent* e, int dir_fd); diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto index 5eb05be1a1d1e4d78a14a4f69f3201f1c96ab449..1754e426fe93fa30cb908a97039a4aa440a8f748 100644 --- a/core/proto/android/app/enums.proto +++ b/core/proto/android/app/enums.proto @@ -32,6 +32,9 @@ enum AppTransitionReasonEnum { APP_TRANSITION_TIMEOUT = 3; // The transition was started because of a we drew a task snapshot. APP_TRANSITION_SNAPSHOT = 4; + // The transition was started because it was a recents animation and we only needed to wait on + // the wallpaper. + APP_TRANSITION_RECENTS_ANIM = 5; } // ActivityManager.java PROCESS_STATEs diff --git a/core/proto/android/content/configuration.proto b/core/proto/android/content/configuration.proto index 74b47d2424b2fa951938b99497416e412be5e7a2..6a174e868a5e52e88ef3e2acf5c22279457b1357 100644 --- a/core/proto/android/content/configuration.proto +++ b/core/proto/android/content/configuration.proto @@ -32,7 +32,7 @@ message ConfigurationProto { optional float font_scale = 1; optional uint32 mcc = 2; - optional uint32 mnc = 3; + optional uint32 mnc = 3 [ (.android.privacy).dest = DEST_EXPLICIT ]; repeated LocaleProto locales = 4; optional uint32 screen_layout = 5; optional uint32 color_mode = 6; diff --git a/core/proto/android/content/intent.proto b/core/proto/android/content/intent.proto index 5e0ed111d7ea0d328ff36031264a48522bd70eaf..3b2c4fcb64cd8f0e212522c15f30e226be28854e 100644 --- a/core/proto/android/content/intent.proto +++ b/core/proto/android/content/intent.proto @@ -59,7 +59,7 @@ message IntentProto { optional ComponentNameProto component = 7; optional string source_bounds = 8; optional string clip_data = 9 [ (.android.privacy).dest = DEST_EXPLICIT ]; - optional string extras = 10 [ (.android.privacy).dest = DEST_EXPLICIT ]; + optional string extras = 10 [ (.android.privacy).dest = DEST_LOCAL ]; optional int32 content_user_hint = 11; optional string selector = 12; } diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto index f468143256a990c472329214e52a0f25b2861a34..345c8ef1860363254023c4e8003f2aedfcf7ddfc 100644 --- a/core/proto/android/os/batterystats.proto +++ b/core/proto/android/os/batterystats.proto @@ -208,32 +208,12 @@ message SystemProto { message DataConnection { option (android.msg_privacy).dest = DEST_AUTOMATIC; - - enum Name { - NONE = 0; - GPRS = 1; - EDGE = 2; - UMTS = 3; - CDMA = 4; - EVDO_0 = 5; - EVDO_A = 6; - ONE_X_RTT = 7; // 1xRTT. - HSDPA = 8; - HSUPA = 9; - HSPA = 10; - IDEN = 11; - EVDO_B = 12; - LTE = 13; - EHRPD = 14; - HSPAP = 15; - GSM = 16; - TD_SCDMA = 17; - IWLAN = 18; - LTE_CA = 19; - OTHER = 20; - }; - optional Name name = 1; - optional TimerProto total = 2; + oneof type { + android.telephony.NetworkTypeEnum name = 1; + // If is_none is not set, then the name is a valid network type. + bool is_none = 2; + } + optional TimerProto total = 3; }; repeated DataConnection data_connection = 8; diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index 4657dc478059cbbe7dbe1aa09cc8c53d7299dc15..6a3aaabb36144fb5395cf5e9ecaa35fe81ffd223 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -118,17 +118,17 @@ message IncidentProto { // Stack dumps optional android.os.BackTraceProto native_traces = 1200 [ - (section).type = SECTION_TOMBSTONE, + (section).type = SECTION_NONE, (section).args = "native" ]; optional android.os.BackTraceProto hal_traces = 1201 [ - (section).type = SECTION_TOMBSTONE, + (section).type = SECTION_NONE, (section).args = "hal" ]; optional android.os.BackTraceProto java_traces = 1202 [ - (section).type = SECTION_TOMBSTONE, + (section).type = SECTION_NONE, (section).args = "java" ]; @@ -169,7 +169,7 @@ message IncidentProto { ]; optional GZippedFileProto last_kmsg = 2007 [ - (section).type = SECTION_GZIP, + (section).type = SECTION_NONE, // disable until selinux permission is gained (section).args = "/sys/fs/pstore/console-ramoops /sys/fs/pstore/console-ramoops-0 /proc/last_kmsg", (privacy).dest = DEST_AUTOMATIC ]; diff --git a/core/proto/android/os/looper.proto b/core/proto/android/os/looper.proto index 435c648d89d8d89033a2d41d682e70434c746449..dce65d35e516b862d3e139d90f642e5c684fcc64 100644 --- a/core/proto/android/os/looper.proto +++ b/core/proto/android/os/looper.proto @@ -25,8 +25,8 @@ import "frameworks/base/libs/incident/proto/android/privacy.proto"; message LooperProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional string thread_name = 1 [ (.android.privacy).dest = DEST_EXPLICIT ]; + // the thread name, usually set by developers. + optional string thread_name = 1; optional int64 thread_id = 2; - optional int32 identity_hash_code = 3; - optional android.os.MessageQueueProto queue = 4; + optional android.os.MessageQueueProto queue = 3; } diff --git a/core/proto/android/os/powermanager.proto b/core/proto/android/os/powermanager.proto index 78a28ed4a0e0737c36a1b123853fd5ace629dac5..20b0a7446ae8b37683ec04c3a286a9aa46cc13ab 100644 --- a/core/proto/android/os/powermanager.proto +++ b/core/proto/android/os/powermanager.proto @@ -36,13 +36,14 @@ message PowerManagerProto { } // WakeLock class in android.os.PowerManager, it is the one used by sdk - message WakeLockProto { + message WakeLock { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional string hex_string = 1; - optional bool held = 2; - optional int32 internal_count = 3; - optional WorkSourceProto work_source = 4; + optional string tag = 1; + optional string package_name = 2; + optional bool held = 3; + optional int32 internal_count = 4; + optional WorkSourceProto work_source = 5; } } diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto index d7ba421ec3c699321dbc6bd0a6aaac98eaf73f02..4e781d67d6938c627cad897f341e324bac411986 100644 --- a/core/proto/android/providers/settings.proto +++ b/core/proto/android/providers/settings.proto @@ -56,386 +56,458 @@ 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_constants = 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 ]; + optional SettingProto sound_trigger_detection_service_op_timeout = 387 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto max_sound_trigger_detection_service_ops_per_day = 388 [ (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 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 ]; + optional SettingsProto backup_agent_timeout_parameters = 386; // Please insert fields in the same order as in // frameworks/base/core/java/android/provider/Settings.java. - // Next tag = 360; + // Next tag = 389; } message SecureSettingsProto { @@ -452,227 +524,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 { @@ -686,29 +760,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 @@ -717,59 +793,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/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 3b9150f44abc325a82cc053431a68061fcb1b94c..fcb980708157377a8e8dc5f9cb06ec7ae2be5412 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -157,7 +157,7 @@ message ReceiverListProto { optional BroadcastRecordProto current = 5; optional bool linked_to_death = 6; repeated BroadcastFilterProto filters = 7; - optional string hex_hash = 8; // this hash is used to find the object in IntentResolver + optional string hex_hash = 8; // used to find this ReceiverList object in IntentResolver } message ProcessRecordProto { @@ -184,7 +184,7 @@ message BroadcastFilterProto { optional .android.content.IntentFilterProto intent_filter = 1; optional string required_permission = 2; - optional string hex_hash = 3; // used to find the object in IntentResolver + optional string hex_hash = 3; // used to find the BroadcastFilter object in IntentResolver optional int32 owning_user_id = 4; } @@ -422,6 +422,8 @@ message ActiveServicesProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; message ServicesByUser { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + optional int32 user_id = 1; repeated ServiceRecordProto service_records = 2; } @@ -458,13 +460,12 @@ message ServiceRecordProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; optional string short_name = 1; - optional string hex_hash = 2; - optional bool is_running = 3; // false if the application service is null - optional int32 pid = 4; - optional .android.content.IntentProto intent = 5; - optional string package_name = 6; - optional string process_name = 7; - optional string permission = 8; + optional bool is_running = 2; // false if the application service is null + optional int32 pid = 3; + optional .android.content.IntentProto intent = 4; + optional string package_name = 5; + optional string process_name = 6; + optional string permission = 7; message AppInfo { option (.android.msg_privacy).dest = DEST_EXPLICIT; @@ -473,11 +474,11 @@ message ServiceRecordProto { optional string res_dir = 2; optional string data_dir = 3; } - optional AppInfo appinfo = 9; - optional ProcessRecordProto app = 10; - optional ProcessRecordProto isolated_proc = 11; - optional bool whitelist_manager = 12; - optional bool delayed = 13; + optional AppInfo appinfo = 8; + optional ProcessRecordProto app = 9; + optional ProcessRecordProto isolated_proc = 10; + optional bool whitelist_manager = 11; + optional bool delayed = 12; message Foreground { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -485,13 +486,13 @@ message ServiceRecordProto { optional int32 id = 1; optional .android.app.NotificationProto notification = 2; } - optional Foreground foreground = 14; + optional Foreground foreground = 13; - optional .android.util.Duration create_real_time = 15; - optional .android.util.Duration starting_bg_timeout = 16; - optional .android.util.Duration last_activity_time = 17; - optional .android.util.Duration restart_time = 18; - optional bool created_from_fg = 19; + optional .android.util.Duration create_real_time = 14; + optional .android.util.Duration starting_bg_timeout = 15; + optional .android.util.Duration last_activity_time = 16; + optional .android.util.Duration restart_time = 17; + optional bool created_from_fg = 18; // variables used to track states related to service start message Start { @@ -503,7 +504,7 @@ message ServiceRecordProto { optional bool call_start = 4; optional int32 last_start_id = 5; } - optional Start start = 20; + optional Start start = 19; message ExecuteNesting { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -512,9 +513,9 @@ message ServiceRecordProto { optional bool execute_fg = 2; optional .android.util.Duration executing_start = 3; } - optional ExecuteNesting execute = 21; + optional ExecuteNesting execute = 20; - optional .android.util.Duration destory_time = 22; + optional .android.util.Duration destory_time = 21; message Crash { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -524,9 +525,9 @@ message ServiceRecordProto { optional .android.util.Duration next_restart_time = 3; optional int32 crash_count = 4; } - optional Crash crash = 23; + optional Crash crash = 22; - message StartItemProto { + message StartItem { option (.android.msg_privacy).dest = DEST_AUTOMATIC; optional int32 id = 1; @@ -537,17 +538,20 @@ message ServiceRecordProto { optional NeededUriGrantsProto needed_grants = 6; optional UriPermissionOwnerProto uri_permissions = 7; } - repeated StartItemProto delivered_starts = 24; - repeated StartItemProto pending_starts = 25; + repeated StartItem delivered_starts = 23; + repeated StartItem pending_starts = 24; + + repeated IntentBindRecordProto bindings = 25; + repeated ConnectionRecordProto connections = 26; - repeated IntentBindRecordProto bindings = 26; - repeated ConnectionRecordProto connections = 27; + // Next Tag: 27 } message ConnectionRecordProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional string hex_hash = 1; + // used to find same record, e.g. AppBindRecord has the hex_hash + optional string hex_hash = 1; // cross reference the object and avoid double logging. optional int32 user_id = 2; enum Flag { @@ -570,30 +574,28 @@ message ConnectionRecordProto { } repeated Flag flags = 3; optional string service_name = 4; - optional string conn_hex_hash = 5; } message AppBindRecordProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional string hex_hash = 1; - optional ProcessRecordProto client = 2; - repeated ConnectionRecordProto connections = 3; + optional string service_name = 1; + optional string client_proc_name = 2; + repeated string connections = 3; // hex_hash of ConnectionRecordProto } message IntentBindRecordProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional string hex_hash = 1; - optional bool is_create = 2; - optional .android.content.IntentProto intent = 3; - optional string binder = 4; - optional bool requested = 5; - optional bool received = 6; - optional bool has_bound = 7; - optional bool do_rebind = 8; + optional .android.content.IntentProto intent = 1; + optional string binder = 2; + optional bool auto_create = 3; // value of BIND_AUTO_CREATE flag. + optional bool requested = 4; + optional bool received = 5; + optional bool has_bound = 6; + optional bool do_rebind = 7; - repeated AppBindRecordProto apps = 9; + repeated AppBindRecordProto apps = 8; } // TODO: "dumpsys activity --proto processes" @@ -688,10 +690,10 @@ message ActivityManagerServiceDumpProcessesProto { optional SleepStatus sleep_status = 27; message VoiceProto { - option (.android.msg_privacy).dest = DEST_EXPLICIT; + option (.android.msg_privacy).dest = DEST_AUTOMATIC; optional string session = 1; - optional .android.os.PowerManagerProto.WakeLockProto wakelock = 2; + optional .android.os.PowerManagerProto.WakeLock wakelock = 2; } optional VoiceProto running_voice = 28; @@ -780,8 +782,8 @@ message ActivityManagerServiceDumpProcessesProto { optional bool call_finish_booting = 44; optional bool boot_animation_complete = 45; optional int64 last_power_check_uptime_ms = 46; - optional .android.os.PowerManagerProto.WakeLockProto going_to_sleep = 47; - optional .android.os.PowerManagerProto.WakeLockProto launching_activity = 48; + optional .android.os.PowerManagerProto.WakeLock going_to_sleep = 47; + optional .android.os.PowerManagerProto.WakeLock launching_activity = 48; optional int32 adj_seq = 49; optional int32 lru_seq = 50; optional int32 num_non_cached_procs = 51; @@ -813,14 +815,13 @@ message ActiveInstrumentationProto { message UidRecordProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional string hex_hash = 1; - optional int32 uid = 2; - optional .android.app.ProcessStateEnum current = 3; - optional bool ephemeral = 4; - optional bool fg_services = 5; - optional bool whilelist = 6; - optional .android.util.Duration last_background_time = 7; - optional bool idle = 8; + optional int32 uid = 1; + optional .android.app.ProcessStateEnum current = 2; + optional bool ephemeral = 3; + optional bool fg_services = 4; + optional bool whilelist = 5; + optional .android.util.Duration last_background_time = 6; + optional bool idle = 7; enum Change { CHANGE_GONE = 0; @@ -829,8 +830,8 @@ message UidRecordProto { CHANGE_CACHED = 3; CHANGE_UNCACHED = 4; } - repeated Change last_reported_changes = 9; - optional int32 num_procs = 10; + repeated Change last_reported_changes = 8; + optional int32 num_procs = 9; message ProcStateSequence { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -839,7 +840,9 @@ message UidRecordProto { optional int64 last_network_updated = 2; optional int64 last_dispatched = 3; } - optional ProcStateSequence network_state_update = 11; + optional ProcStateSequence network_state_update = 10; + + // Next Tag: 11 } // proto of class ImportanceToken in ActivityManagerService diff --git a/core/proto/android/server/animationadapter.proto b/core/proto/android/server/animationadapter.proto new file mode 100644 index 0000000000000000000000000000000000000000..c4ffe8c477aa1fc25f3c95e7dac4cc80cc2b3b27 --- /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/intentresolver.proto b/core/proto/android/server/intentresolver.proto index 0ada89533cb4ee58013a282284ba8d3fcfb153d6..e67723e5abfad56bd8a3ab8cdd76758a43a098a0 100644 --- a/core/proto/android/server/intentresolver.proto +++ b/core/proto/android/server/intentresolver.proto @@ -24,9 +24,9 @@ import "frameworks/base/libs/incident/proto/android/privacy.proto"; message IntentResolverProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - + // A mapping bewteen some key string to IntentFilter's toString(). message ArrayMapEntry { - option (.android.msg_privacy).dest = DEST_EXPLICIT; + option (.android.msg_privacy).dest = DEST_AUTOMATIC; optional string key = 1; repeated string values = 2; diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto index 5cb5319f4feac0807da8a80146c2b1430a40fdbd..c58de563692b8124d4976f66ab9fa7da3536bc0c 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 @@ -315,4 +315,6 @@ message PowerServiceSettingsAndConfigurationDumpProto { optional bool is_double_tap_wake_enabled = 37; // True if we are currently in VR Mode. optional bool is_vr_mode_enabled = 38; + // True if Sidekick is controlling the display and we shouldn't change its power mode. + optional bool draw_wake_lock_override_from_sidekick = 39; } diff --git a/core/proto/android/server/surfaceanimator.proto b/core/proto/android/server/surfaceanimator.proto index 7f7839e6f7f165d2c45cfd9b729bf099ed3a5033..dcc2b3443f2b2f808f15f30c5cc73a9809228045 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/service/diskstats.proto b/core/proto/android/service/diskstats.proto index 3d7ee914074e684d101216c813438c25771838b9..f55f0e775d78e170e0f67107c75738c3baa061ac 100644 --- a/core/proto/android/service/diskstats.proto +++ b/core/proto/android/service/diskstats.proto @@ -37,8 +37,8 @@ message DiskStatsServiceDumpProto { } // Whether the latency test resulted in an error optional bool has_test_error = 1; - // If the test errored, error message is contained here - optional string error_message = 2 [ (android.privacy).dest = DEST_EXPLICIT ]; + // If the test errored, error message is contained here, it is just IOException. + optional string error_message = 2; // 512B write latency in milliseconds, if the test was successful optional int32 write_512b_latency_millis = 3; // Free Space in the major partitions @@ -55,25 +55,25 @@ message DiskStatsCachedValuesProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; // Total app code size, in kilobytes - optional int64 agg_apps_size = 1; + optional int64 agg_apps_size_kb = 1; // Total app cache size, in kilobytes - optional int64 agg_apps_cache_size = 2; + optional int64 agg_apps_cache_size_kb = 2; // Size of image files, in kilobytes - optional int64 photos_size = 3; + optional int64 photos_size_kb = 3; // Size of video files, in kilobytes - optional int64 videos_size = 4; + optional int64 videos_size_kb = 4; // Size of audio files, in kilobytes - optional int64 audio_size = 5; + optional int64 audio_size_kb = 5; // Size of downloads, in kilobytes - optional int64 downloads_size = 6; + optional int64 downloads_size_kb = 6; // Size of system directory, in kilobytes - optional int64 system_size = 7; + optional int64 system_size_kb = 7; // Size of other files, in kilobytes - optional int64 other_size = 8; + optional int64 other_size_kb = 8; // Sizes of individual packages repeated DiskStatsAppSizesProto app_sizes = 9; // Total app data size, in kilobytes - optional int64 agg_apps_data_size = 10; + optional int64 agg_apps_data_size_kb = 10; } message DiskStatsAppSizesProto { @@ -82,11 +82,11 @@ message DiskStatsAppSizesProto { // Name of the package optional string package_name = 1; // App's code size in kilobytes - optional int64 app_size = 2; + optional int64 app_size_kb = 2; // App's cache size in kilobytes - optional int64 cache_size = 3; + optional int64 cache_size_kb = 3; // App's data size in kilobytes - optional int64 app_data_size = 4; + optional int64 app_data_size_kb = 4; } message DiskStatsFreeSpaceProto { @@ -103,7 +103,7 @@ message DiskStatsFreeSpaceProto { // Which folder? optional Folder folder = 1; // Available space, in kilobytes - optional int64 available_space = 2; + optional int64 available_space_kb = 2; // Total space, in kilobytes - optional int64 total_space = 3; + optional int64 total_space_kb = 3; } diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto index f42206562fc47b1dcfe22506f4836aca534e464d..c2fedf5a57223d3494ef60948ab110991ee0261b 100644 --- a/core/proto/android/service/graphicsstats.proto +++ b/core/proto/android/service/graphicsstats.proto @@ -56,7 +56,7 @@ message GraphicsStatsJankSummaryProto { // Number of "missed vsync" events. optional int32 missed_vsync_count = 3; - // Number of "high input latency" events. + // Number of frames in triple-buffering scenario (high input latency) optional int32 high_input_latency_count = 4; // Number of "slow UI thread" events. @@ -67,6 +67,9 @@ message GraphicsStatsJankSummaryProto { // Number of "slow draw" events. optional int32 slow_draw_count = 7; + + // Number of frames that missed their deadline (aka, visibly janked) + optional int32 missed_deadline_count = 8; } message GraphicsStatsHistogramBucketProto { diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto index 5c40e5fe346f21a6eedba8f88335f227462583a7..cccd2fe56800333b58beee35d59efb03f4d446f8 100644 --- a/core/proto/android/service/notification.proto +++ b/core/proto/android/service/notification.proto @@ -93,7 +93,8 @@ message ManagedServicesProto { message ServiceProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; - repeated string name = 1 [ (.android.privacy).dest = DEST_EXPLICIT ]; + // Package or component name. + repeated string name = 1; optional int32 user_id = 2; optional bool is_primary = 3; } @@ -169,16 +170,16 @@ message ConditionProto { message ZenRuleProto { option (android.msg_privacy).dest = DEST_EXPLICIT; - // Required for automatic (unique). + // Required for automatic ZenRules (unique). optional string id = 1; - // Required for automatic. + // Required for automatic ZenRules. optional string name = 2; - // Required for automatic. + // Required for automatic ZenRules. optional int64 creation_time_ms = 3 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional bool enabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; - // Package name, only used for manual rules. + // Package name, only used for manual ZenRules. optional string enabler = 5 [ (android.privacy).dest = DEST_AUTOMATIC ]; // User manually disabled this instance. optional bool is_snoozing = 6 [ @@ -188,7 +189,7 @@ message ZenRuleProto { (android.privacy).dest = DEST_AUTOMATIC ]; - // Required for automatic. + // Required for automatic ZenRules. optional string condition_id = 8; optional ConditionProto condition = 9; optional android.content.ComponentNameProto component = 10; diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto index 60f8d8d78545a97252e66917294ef96d7de07081..32975a5550f1dce083c66b972e4607ba28a5b47d 100644 --- a/core/proto/android/telephony/enums.proto +++ b/core/proto/android/telephony/enums.proto @@ -28,6 +28,31 @@ enum DataConnectionPowerStateEnum { DATA_CONNECTION_POWER_STATE_UNKNOWN = 2147483647; // Java Integer.MAX_VALUE; } +// Network type enums, primarily used by android/telephony/TelephonyManager.java. +// Do not add negative types. +enum NetworkTypeEnum { + NETWORK_TYPE_UNKNOWN = 0; + NETWORK_TYPE_GPRS = 1; + NETWORK_TYPE_EDGE = 2; + NETWORK_TYPE_UMTS = 3; + NETWORK_TYPE_CDMA = 4; + NETWORK_TYPE_EVDO_0 = 5; + NETWORK_TYPE_EVDO_A = 6; + NETWORK_TYPE_1XRTT = 7; + NETWORK_TYPE_HSDPA = 8; + NETWORK_TYPE_HSUPA = 9; + NETWORK_TYPE_HSPA = 10; + NETWORK_TYPE_IDEN = 11; + NETWORK_TYPE_EVDO_B = 12; + NETWORK_TYPE_LTE = 13; + NETWORK_TYPE_EHRPD = 14; + NETWORK_TYPE_HSPAP = 15; + NETWORK_TYPE_GSM = 16; + NETWORK_TYPE_TD_SCDMA = 17; + NETWORK_TYPE_IWLAN = 18; + NETWORK_TYPE_LTE_CA = 19; +} + // Signal strength levels, primarily used by android/telephony/SignalStrength.java. enum SignalStrengthEnum { SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0; 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 0000000000000000000000000000000000000000..d5da0a9a7f73f7e9111c9bb72c2342974b5d978e --- /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 cd32777956d5f8dfe0cf40b06e5f80fce9c08233..4e5b41be69f0cb5bde1362a1ff61d94932be169f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2572,6 +2572,12 @@ + + + + @SystemApi + @TestApi --> @@ -3122,7 +3129,8 @@ + @SystemApi + @TestApi --> @@ -3766,10 +3774,17 @@ + @hide + @SystemApi --> + + + diff --git a/core/res/res/drawable/floating_popup_background_dark.xml b/core/res/res/drawable/floating_popup_background_dark.xml index ded1137576de63e486d7229182b63d1088011d35..c4b44484d046285ed4bf6b44bd96dcf8a1868c0a 100644 --- a/core/res/res/drawable/floating_popup_background_dark.xml +++ b/core/res/res/drawable/floating_popup_background_dark.xml @@ -16,8 +16,8 @@ */ --> + android:shape="rectangle"> - + diff --git a/core/res/res/drawable/floating_popup_background_light.xml b/core/res/res/drawable/floating_popup_background_light.xml index 9c7a8860dde785b3ca43cd0de756e00ece875d34..767140d9d5c13d36905eb944c58e5fc6695c453b 100644 --- a/core/res/res/drawable/floating_popup_background_light.xml +++ b/core/res/res/drawable/floating_popup_background_light.xml @@ -18,6 +18,6 @@ - + diff --git a/core/res/res/drawable/ic_corp_user_badge.xml b/core/res/res/drawable/ic_corp_user_badge.xml index 6a0d9025684d397924313fdefc5dafaec1d6be66..a08f2d4845e1fc6dd73b5c76745a734348d6156f 100644 --- a/core/res/res/drawable/ic_corp_user_badge.xml +++ b/core/res/res/drawable/ic_corp_user_badge.xml @@ -2,7 +2,8 @@ android:width="36dp" android:height="36dp" android:viewportWidth="36.0" - android:viewportHeight="36.0"> + android:viewportHeight="36.0" + android:tint="?attr/colorControlNormal"> diff --git a/core/res/res/layout/shutdown_dialog.xml b/core/res/res/layout/shutdown_dialog.xml index 398bfb1824c7784dd4a2ef228dc8800f295ca9d2..2d214b32164b8f634d806a83b140d5f39de79f86 100644 --- a/core/res/res/layout/shutdown_dialog.xml +++ b/core/res/res/layout/shutdown_dialog.xml @@ -29,7 +29,7 @@ - - + - + diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b9468dcfd67a7b6aff44f168b10ad47f96ba0e59..c5a0188ea464f38a00df13a9fb5c34694ece741b 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1277,7 +1277,7 @@ in darkness (although they may not be visible in a bright room). --> 1 - - - 0x35 + Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT --> + 0x55 diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a5bd179826b14683f608c53c799668d9a6b80260..aac4092db08fa41662dfadcdd53cc473532aaa0b 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -148,25 +148,25 @@ You can\'t change the caller ID setting. - No data service + No mobile data service - No emergency calling + Emergency calling unavailable No voice service - No voice/emergency service + No voice service or emergency calling - Temporarily not offered by the mobile network at your location + Temporarily turned off by your carrier - Can\u2019t reach network + Can\u2019t reach mobile network - To improve reception, try changing the type selected at Settings > Network & internet > Mobile networks > Preferred network type." + Try changing preferred network. Tap to change. - Wi\u2011Fi calling is active + Emergency calling unavailable - Emergency calls require a mobile network. + Can\u2019t make emergency calls over Wi\u2011Fi Alerts @@ -319,9 +319,9 @@ Sync - Sync + Can\'t sync - Too many %s deletes. + Attempted to delete too many %s. Tablet storage is full. Delete some files to free space. @@ -352,9 +352,6 @@ Work profile deleted - - Work profile deleted due to missing admin app The work profile admin app is either missing or corrupted. @@ -673,7 +670,7 @@ access your contacts Allow - <b>%1$s</b> to access your contacts + <b>%1$s</b> to access your contacts? Location @@ -681,7 +678,7 @@ access this device\'s location Allow - <b>%1$s</b> to access this device\'s location + <b>%1$s</b> to access this device\'s location? Calendar @@ -689,7 +686,7 @@ access your calendar Allow - <b>%1$s</b> to access your calendar + <b>%1$s</b> to access your calendar? SMS @@ -697,7 +694,7 @@ send and view SMS messages Allow - <b>%1$s</b> to send and view SMS messages + <b>%1$s</b> to send and view SMS messages? Storage @@ -705,7 +702,7 @@ access photos, media, and files on your device Allow - <b>%1$s</b> to access photos, media, and files on your device + <b>%1$s</b> to access photos, media, and files on your device? Microphone @@ -713,7 +710,7 @@ record audio Allow - <b>%1$s</b> to record audio + <b>%1$s</b> to record audio? Camera @@ -721,7 +718,7 @@ take pictures and record video Allow - <b>%1$s</b> to take pictures and record video + <b>%1$s</b> to take pictures and record video? Phone @@ -729,7 +726,7 @@ make and manage phone calls Allow - <b>%1$s</b> to make and manage phone calls + <b>%1$s</b> to make and manage phone calls? Body Sensors @@ -737,7 +734,7 @@ access sensor data about your vital signs Allow - <b>%1$s</b> to access sensor data about your vital signs + <b>%1$s</b> to access sensor data about your vital signs? Retrieve window content @@ -2447,6 +2444,18 @@ More Menu+ + + Meta+ + + Ctrl+ + + Alt+ + + Shift+ + + Sym+ + + Function+ space @@ -2998,8 +3007,7 @@ limit - Heap dump has been collected; - tap to share + Heap dump collected. Tap to share. Share heap dump? @@ -3270,7 +3278,7 @@ MIDI via USB turned on - USB accessory mode turned on + USB accessory connected Tap for more options. @@ -3284,7 +3292,7 @@ USB debugging connected - Tap to disable USB debugging. + Tap to turn off USB debugging Select to disable USB debugging. @@ -3565,7 +3573,7 @@ Disconnected from always-on VPN - Always-on VPN error + Couldn\'t connect to always-on VPN Change network or VPN settings @@ -3582,8 +3590,8 @@ - Car mode enabled - Tap to exit car mode. + Driving app is running + Tap to exit driving app. @@ -4490,7 +4498,7 @@ - For one hour (until %2$s) + For 1 hour (until %2$s) For %1$d hours (until %2$s) @@ -4514,7 +4522,7 @@ - For one hour + For 1 hour For %d hours @@ -4880,10 +4888,21 @@ Edit - + System changes + + Do Not Disturb + + Do Not Disturb is hiding notifications to help you focus + + This is new behavior. Tap to change. - Do Not Disturb is hiding notifications to help you focus + Do Not Disturb has changed - This is a new feature from the latest system update. Tap to change. + Tap to check what\'s blocked. + + + System + + Settings diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f04f1caefa1063d0b2ae638909f42a99d40127e2..774710b8a93565ec6114236d3215cf226884c515 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -528,9 +528,15 @@ + + + + + + @@ -3123,6 +3129,7 @@ + @@ -3225,6 +3232,7 @@ + @@ -3291,7 +3299,12 @@ + + + + + diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index fdbcd8a27f912d615f1894d4e156fab7898983fb..25b053b0f0c5ef5d5513543f685897861f2e1eac 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -1318,6 +1318,9 @@ easier. @color/config_progress_background_tint @dimen/config_progressBarCornerRadius + + + @color/primary_material_light - + + diff --git a/packages/SystemUI/res/values/styles_car.xml b/packages/SystemUI/res/values/styles_car.xml index c66792ca6a158789ed0649c798ab2238a8e391d0..2aaef86296f3c402247bf802dc12535a79be1f6f 100644 --- a/packages/SystemUI/res/values/styles_car.xml +++ b/packages/SystemUI/res/values/styles_car.xml @@ -16,14 +16,6 @@ --> - - \ No newline at end of file diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 4be7287ae7a56a48f81a8be6146492e4a64162be..0cc60e3146d78c26d0172a62827adceabdf17650 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5363,7 +5363,6 @@ message MetricsEvent { // OS: P ACTION_PANEL_VIEW_EXPAND = 1328; - // FIELD: Rotation of the device // CATEGORY: GLOBAL_SYSTEM_UI // OS: P @@ -5500,6 +5499,48 @@ 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; + + // OPEN: Settings > Gestures > Prevent Ringing + // OS: P + SETTINGS_PREVENT_RINGING = 1360; + + // ACTION: Settings > Battery settings > Battery tip > Open app restriction page + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_OPEN_APP_RESTRICTION_PAGE = 1361; + + // ACTION: Settings > Battery settings > Battery tip > Restrict app + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_RESTRICT_APP = 1362; + + // ACTION: Settings > Battery settings > Battery tip > Unrestrict app + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_UNRESTRICT_APP = 1363; + + // ACTION: Settings > Battery settings > Battery tip > Open smart battery page + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_OPEN_SMART_BATTERY = 1364; + + // ACTION: Settings > Battery settings > Battery tip > Turn on battery saver + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_TURN_ON_BATTERY_SAVER = 1365; + + // FIELD: type of anomaly in settings app + // CATEGORY: SETTINGS + // OS: P + FIELD_ANOMALY_TYPE = 1366; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto index c9d5c272d48c984d5b177ea1012346a3ac964ef4..490a59e770ecccf61b9b585562c815fe89817b98 100644 --- a/proto/src/task_snapshot.proto +++ b/proto/src/task_snapshot.proto @@ -27,4 +27,5 @@ int32 inset_top = 3; int32 inset_right = 4; int32 inset_bottom = 5; + bool is_real_snapshot = 6; } \ No newline at end of file diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 74efec93f201d5dc4e29f0ff2d7ba67c298a99cc..0763fa129f657394f7c665dbca806a9caa626d2e 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -926,6 +926,34 @@ message WifiAwareLog { // total time within the logging window that aware was enabled optional int64 enabled_time_ms = 40; + // maximum number of concurrent publish sessions enabling ranging in a single app + optional int32 max_concurrent_publish_with_ranging_in_app = 41; + + // maximum number of concurrent subscribe sessions specifying a geofence in a single app + optional int32 max_concurrent_subscribe_with_ranging_in_app = 42; + + // maximum number of concurrent publish sessions enabling ranging in the system + optional int32 max_concurrent_publish_with_ranging_in_system = 43; + + // maximum number of concurrent subscribe sessions specifying a geofence in the system + optional int32 max_concurrent_subscribe_with_ranging_in_system = 44; + + // histogram of subscribe session geofence minimum (only when specified) + repeated HistogramBucket histogram_subscribe_geofence_min = 45; + + // histogram of subscribe session geofence maximum (only when specified) + repeated HistogramBucket histogram_subscribe_geofence_max = 46; + + // total number of subscribe sessions which enabled ranging + optional int32 num_subscribes_with_ranging = 47; + + // total number of matches (service discovery indication) with ranging provided + optional int32 num_matches_with_ranging = 48; + + // total number of matches (service discovery indication) for service discovery with ranging + // enabled which did not trigger ranging + optional int32 num_matches_without_ranging_for_ranging_enabled_subscribes = 49; + // Histogram bucket for Wi-Fi Aware logs. Range is [start, end) message HistogramBucket { // lower range of the bucket (inclusive) diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index ed068b931bad56fb4cd88e75d1518bad3aafcc3b..5c5978ad1adc762adfbca724ef0dae47e4bc6ed5 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -88,7 +88,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ final int mId; - final AccessibilityServiceInfo mAccessibilityServiceInfo; + protected final AccessibilityServiceInfo mAccessibilityServiceInfo; // Lock must match the one used by AccessibilityManagerService protected final Object mLock; @@ -340,6 +340,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } } + public int getCapabilities() { + return mAccessibilityServiceInfo.getCapabilities(); + } + int getRelevantEventTypes() { return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK : 0) | mEventTypes; diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index b0b95868600fadb971fc5ecf317673d38a989b08..8941b49265845d3942e4c9142163445de05b5f62 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -621,7 +621,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub for (int i = 0; i < serviceCount; ++i) { final AccessibilityServiceConnection service = services.get(i); if ((service.mFeedbackType & feedbackType) != 0) { - result.add(service.mAccessibilityServiceInfo); + result.add(service.getServiceInfo()); } } return result; @@ -1874,7 +1874,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final int serviceCount = userState.mBoundServices.size(); for (int i = 0; i < serviceCount; i++) { AccessibilityServiceConnection service = userState.mBoundServices.get(i); - if ((service.mAccessibilityServiceInfo.getCapabilities() + if ((service.getCapabilities() & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0) { userState.mIsPerformGesturesEnabled = true; return; @@ -1888,7 +1888,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub for (int i = 0; i < serviceCount; i++) { AccessibilityServiceConnection service = userState.mBoundServices.get(i); if (service.mRequestFilterKeyEvents - && (service.mAccessibilityServiceInfo.getCapabilities() + && (service.getCapabilities() & AccessibilityServiceInfo .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) != 0) { userState.mIsFilterKeyEventsEnabled = true; @@ -2124,7 +2124,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // Starting in JB-MR2 we request an accessibility service to declare // certain capabilities in its meta-data to allow it to enable the // corresponding features. - if ((service.mAccessibilityServiceInfo.getCapabilities() + if ((service.getCapabilities() & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) { return true; } @@ -3129,6 +3129,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub boolean activeWindowGone = true; final int windowCount = windows.size(); + + // We'll clear accessibility focus if the window with focus is no longer visible to + // accessibility services + boolean shouldClearAccessibilityFocus = + mAccessibilityFocusedWindowId != INVALID_WINDOW_ID; if (windowCount > 0) { for (int i = 0; i < windowCount; i++) { WindowInfo windowInfo = windows.get(i); @@ -3166,6 +3171,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } if (window.getId() == mAccessibilityFocusedWindowId) { window.setAccessibilityFocused(true); + shouldClearAccessibilityFocus = false; } } } @@ -3176,6 +3182,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub for (int i = oldWindowCount - 1; i >= 0; i--) { oldWindowList.remove(i).recycle(); } + + if (shouldClearAccessibilityFocus) { + clearAccessibilityFocus(mAccessibilityFocusedWindowId); + } } private void sendEventsForChangedWindowsLocked(List oldWindows, @@ -3436,22 +3446,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } public boolean canRetrieveWindowContentLocked(AbstractAccessibilityServiceConnection service) { - return (service.mAccessibilityServiceInfo.getCapabilities() + return (service.getCapabilities() & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; } public boolean canControlMagnification(AbstractAccessibilityServiceConnection service) { - return (service.mAccessibilityServiceInfo.getCapabilities() + return (service.getCapabilities() & AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION) != 0; } public boolean canPerformGestures(AccessibilityServiceConnection service) { - return (service.mAccessibilityServiceInfo.getCapabilities() + return (service.getCapabilities() & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0; } public boolean canCaptureFingerprintGestures(AccessibilityServiceConnection service) { - return (service.mAccessibilityServiceInfo.getCapabilities() + return (service.getCapabilities() & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES) != 0; } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java index 89bf82d6f065e17eebfe32db687c09aa583b9b1f..eb18f06baae0cbc582a8fea030b186ae7434c9d7 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java @@ -165,7 +165,14 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect } } - public void initializeService() { + @Override + public AccessibilityServiceInfo getServiceInfo() { + // Update crashed data + mAccessibilityServiceInfo.crashed = mWasConnectedAndDied; + return mAccessibilityServiceInfo; + } + + private void initializeService() { IAccessibilityServiceClient serviceInterface = null; synchronized (mLock) { UserState userState = mUserStateWeakReference.get(); diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java index 5b5d18f4aaf7c7a216a5e5f2fedbf07de9f51999..9f441978f3aa083a6c38246f8e48f82e40e68f47 100644 --- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java @@ -55,7 +55,7 @@ import java.util.Locale; * magnification region. If a value is out of bounds, it will be adjusted to guarantee these * constraints. */ -class MagnificationController implements Handler.Callback { +public class MagnificationController implements Handler.Callback { private static final boolean DEBUG = false; private static final String LOG_TAG = "MagnificationController"; diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 266b2d791991ed3471701ece341563fa02c693f1..a5339e0e65496004c6185a982860a2e90919170c 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -59,9 +59,7 @@ import android.service.autofill.UserData; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.LocalLog; -import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -73,6 +71,7 @@ import android.view.autofill.IAutoFillManager; import android.view.autofill.IAutoFillManagerClient; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; import com.android.internal.os.IResultReceiver; @@ -88,8 +87,8 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Objects; -import java.util.Set; /** * Entry point service for autofill management. @@ -105,6 +104,13 @@ public final class AutofillManagerService extends SystemService { static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions"; private static final char COMPAT_PACKAGE_DELIMITER = ':'; + private static final char COMPAT_PACKAGE_URL_IDS_DELIMITER = ','; + private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '['; + private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']'; + + // TODO(b/74445943): temporary work around until P Development Preview 3 is branched + private static final List DEFAULT_BUTTONS = Arrays.asList("url_bar", + "location_bar_edit_text"); private final Context mContext; private final AutoFillUI mUi; @@ -326,7 +332,7 @@ public final class AutofillManagerService extends SystemService { if (service == null) { service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory, mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, - mDisabledUsers.get(resolvedUserId)); + mAutofillCompatState, mDisabledUsers.get(resolvedUserId)); mServicesCache.put(userId, service); addCompatibilityModeRequestsLocked(service, userId); } @@ -544,23 +550,24 @@ public final class AutofillManagerService extends SystemService { private void addCompatibilityModeRequestsLocked(@NonNull AutofillManagerServiceImpl service , int userId) { mAutofillCompatState.reset(); - final ArrayMap> compatPackages = + final ArrayMap compatPackages = service.getCompatibilityPackagesLocked(); if (compatPackages == null || compatPackages.isEmpty()) { return; } - final Set whiteListedPackages = getWhitelistedCompatModePackages(); + + final Map whiteListedPackages = getWhitelistedCompatModePackages(); final int compatPackageCount = compatPackages.size(); for (int i = 0; i < compatPackageCount; i++) { final String packageName = compatPackages.keyAt(i); - if (whiteListedPackages == null || !whiteListedPackages.contains(packageName)) { + if (whiteListedPackages == null || !whiteListedPackages.containsKey(packageName)) { Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName); continue; } - final Long maxVersionCode = compatPackages.valueAt(i).first; + final Long maxVersionCode = compatPackages.valueAt(i); if (maxVersionCode != null) { mAutofillCompatState.addCompatibilityModeRequest(packageName, - maxVersionCode, userId); + maxVersionCode, whiteListedPackages.get(packageName), userId); } } } @@ -571,16 +578,60 @@ public final class AutofillManagerService extends SystemService { Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES); } - private @Nullable Set getWhitelistedCompatModePackages() { - final String compatPackagesSetting = getWhitelistedCompatModePackagesFromSettings(); - if (TextUtils.isEmpty(compatPackagesSetting)) { + @Nullable + private Map getWhitelistedCompatModePackages() { + return getWhitelistedCompatModePackages(getWhitelistedCompatModePackagesFromSettings()); + } + + @Nullable + @VisibleForTesting + static Map getWhitelistedCompatModePackages(String setting) { + if (TextUtils.isEmpty(setting)) { return null; } - final Set compatPackages = new ArraySet<>(); + + final ArrayMap compatPackages = new ArrayMap<>(); final SimpleStringSplitter splitter = new SimpleStringSplitter(COMPAT_PACKAGE_DELIMITER); - splitter.setString(compatPackagesSetting); + splitter.setString(setting); while (splitter.hasNext()) { - compatPackages.add(splitter.next()); + final String packageBlock = splitter.next(); + final int urlBlockIndex = packageBlock.indexOf(COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN); + final String packageName; + final List urlBarIds; + if (urlBlockIndex == -1) { + packageName = packageBlock; + urlBarIds = DEFAULT_BUTTONS; // TODO(b/74445943): back to null + } else { + if (packageBlock.charAt(packageBlock.length() - 1) + != COMPAT_PACKAGE_URL_IDS_BLOCK_END) { + Slog.w(TAG, "Ignoring entry '" + packageBlock + "' on '" + setting + + "'because it does not end on '" + COMPAT_PACKAGE_URL_IDS_BLOCK_END + + "'"); + continue; + } + packageName = packageBlock.substring(0, urlBlockIndex); + urlBarIds = new ArrayList<>(); + final String urlBarIdsBlock = + packageBlock.substring(urlBlockIndex + 1, packageBlock.length() - 1); + if (sVerbose) { + Slog.v(TAG, "pkg:" + packageName + ": block:" + packageBlock + ": urls:" + + urlBarIds + ": block:" + urlBarIdsBlock + ":"); + } + final SimpleStringSplitter splitter2 = + new SimpleStringSplitter(COMPAT_PACKAGE_URL_IDS_DELIMITER); + splitter2.setString(urlBarIdsBlock); + while (splitter2.hasNext()) { + final String urlBarId = splitter2.next(); + urlBarIds.add(urlBarId); + } + } + if (urlBarIds == null) { + compatPackages.put(packageName, null); + } else { + final String[] urlBarIdsArray = new String[urlBarIds.size()]; + urlBarIds.toArray(urlBarIdsArray); + compatPackages.put(packageName, urlBarIdsArray); + } } return compatPackages; } @@ -598,13 +649,41 @@ public final class AutofillManagerService extends SystemService { return mAutofillCompatState.isCompatibilityModeRequested( packageName, versionCode, userId); } + } - private static final class AutofillCompatState { + /** + * Compatibility mode metadata per package. + */ + private static final class PackageCompatState { + private final long maxVersionCode; + private final String[] urlBarResourceIds; + + PackageCompatState(long maxVersionCode, String[] urlBarResourceIds) { + this.maxVersionCode = maxVersionCode; + this.urlBarResourceIds = urlBarResourceIds; + } + + @Override + public String toString() { + return "PackageCompatState: [maxVersionCode=" + maxVersionCode + + ", urlBarResourceIds=" + Arrays.toString(urlBarResourceIds) + "]"; + } + } + + /** + * Compatibility mode metadata associated with all services. + * + *

    This object is defined here instead of on each {@link AutofillManagerServiceImpl} because + * it cannot hold a lock on the main lock when + * {@link AutofillCompatState#isCompatibilityModeRequested(String, long, int)} is called by + * external services. + */ + static final class AutofillCompatState { private final Object mLock = new Object(); @GuardedBy("mLock") - private SparseArray> mUserSpecs; + private SparseArray> mUserSpecs; boolean isCompatibilityModeRequested(@NonNull String packageName, long versionCode, @UserIdInt int userId) { @@ -612,30 +691,49 @@ public final class AutofillManagerService extends SystemService { if (mUserSpecs == null) { return false; } - final ArrayMap userSpec = mUserSpecs.get(userId); + final ArrayMap userSpec = mUserSpecs.get(userId); if (userSpec == null) { return false; } - final Long maxVersionCode = userSpec.get(packageName); - if (maxVersionCode == null) { + final PackageCompatState metadata = userSpec.get(packageName); + if (metadata == null) { return false; } - return versionCode <= maxVersionCode; + return versionCode <= metadata.maxVersionCode; + } + } + + @Nullable + String[] getUrlBarResourceIds(@NonNull String packageName, @UserIdInt int userId) { + synchronized (mLock) { + if (mUserSpecs == null) { + return null; + } + final ArrayMap userSpec = mUserSpecs.get(userId); + if (userSpec == null) { + return null; + } + final PackageCompatState metadata = userSpec.get(packageName); + if (metadata == null) { + return null; + } + return metadata.urlBarResourceIds; } } void addCompatibilityModeRequest(@NonNull String packageName, - long versionCode, @UserIdInt int userId) { + long versionCode, @Nullable String[] urlBarResourceIds, @UserIdInt int userId) { synchronized (mLock) { if (mUserSpecs == null) { mUserSpecs = new SparseArray<>(); } - ArrayMap userSpec = mUserSpecs.get(userId); + ArrayMap userSpec = mUserSpecs.get(userId); if (userSpec == null) { userSpec = new ArrayMap<>(); mUserSpecs.put(userId, userSpec); } - userSpec.put(packageName, versionCode); + userSpec.put(packageName, + new PackageCompatState(versionCode, urlBarResourceIds)); } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 8622dbe820a68e72c0a6ad8040115d5a18aefcb7..54ea3ba4546b55b57011b7876bed76d642028d4e 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -64,7 +64,6 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; import android.util.LocalLog; -import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; @@ -78,12 +77,12 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.LocalServices; +import com.android.server.autofill.AutofillManagerService.AutofillCompatState; import com.android.server.autofill.ui.AutoFillUI; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Random; /** @@ -164,12 +163,15 @@ final class AutofillManagerServiceImpl { @GuardedBy("mLock") private FillEventHistory mEventHistory; + /** Shared instance, doesn't need to be logged */ + private final AutofillCompatState mAutofillCompatState; + /** When was {@link PruneTask} last executed? */ private long mLastPrune = 0; AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory, LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui, - boolean disabled) { + AutofillCompatState autofillCompatState, boolean disabled) { mContext = context; mLock = lock; mRequestsHistory = requestsHistory; @@ -178,6 +180,7 @@ final class AutofillManagerServiceImpl { mUserId = userId; mUi = ui; mFieldClassificationStrategy = new FieldClassificationStrategy(context, userId); + mAutofillCompatState = autofillCompatState; updateLocked(disabled); } @@ -208,14 +211,9 @@ final class AutofillManagerServiceImpl { } - @GuardedBy("mLock") @Nullable - String getUrlBarResourceIdForCompatModeLocked(@NonNull String packageName) { - if (mInfo == null) { - Slog.w(TAG, "getUrlBarResourceIdForCompatModeLocked(): no mInfo"); - return null; - } - return mInfo.getUrlBarResourceId(packageName); + String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) { + return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId); } @Nullable @@ -893,7 +891,7 @@ final class AutofillManagerServiceImpl { pw.print(prefix); pw.print("Field classification enabled: "); pw.println(isFieldClassificationEnabledLocked()); pw.print(prefix); pw.print("Compat pkgs: "); - final ArrayMap> compatPkgs = getCompatibilityPackagesLocked(); + final ArrayMap compatPkgs = getCompatibilityPackagesLocked(); if (compatPkgs == null) { pw.println("N/A"); } else { @@ -1022,7 +1020,7 @@ final class AutofillManagerServiceImpl { } @GuardedBy("mLock") - @Nullable ArrayMap> getCompatibilityPackagesLocked() { + @Nullable ArrayMap getCompatibilityPackagesLocked() { if (mInfo != null) { return mInfo.getCompatibilityPackages(); } diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java index 232dfdcf045bdffc212602fbf2cb1c05b3b0a89d..5c41f3f869cefde01e928389e88f1c24ac14f99e 100644 --- a/services/autofill/java/com/android/server/autofill/Helper.java +++ b/services/autofill/java/com/android/server/autofill/Helper.java @@ -30,6 +30,7 @@ import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.util.ArrayUtils; import java.io.PrintWriter; import java.util.ArrayList; @@ -168,21 +169,24 @@ public final class Helper { /** * Sanitize the {@code webDomain} property of the URL bar node on compat mode. + * + * @param structure Assist structure + * @param urlBarIds list of ids; only the first id found will be sanitized. */ public static void sanitizeUrlBar(@NonNull AssistStructure structure, - @NonNull String urlBarId) { + @NonNull String[] urlBarIds) { final ViewNode urlBarNode = findViewNode(structure, (node) -> { - return urlBarId.equals(node.getIdEntry()); + return ArrayUtils.contains(urlBarIds, node.getIdEntry()); }); if (urlBarNode != null) { final String domain = urlBarNode.getText().toString(); if (domain.isEmpty()) { - if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarId); + if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarNode.getIdEntry()); return; } urlBarNode.setWebDomain(domain); if (sDebug) { - Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarId + ", domain=" + Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarNode.getIdEntry() + ", domain=" + urlBarNode.getWebDomain()); } } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 4abf0f8e8f1abf0a9fad64f52fe568a29d66eb49..7f57615163022a5372b3963fcc8907bedc3fd6a0 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -274,11 +274,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } if (mCompatMode) { // Sanitize URL bar, if needed - final String urlBarId = mService.getUrlBarResourceIdForCompatModeLocked( + final String[] urlBarIds = mService.getUrlBarResourceIdsForCompatMode( mComponentName.getPackageName()); - if (sDebug) Slog.d(TAG, "url_bar in compat mode: " + urlBarId); - if (urlBarId != null) { - Helper.sanitizeUrlBar(structure, urlBarId); + if (sDebug) { + Slog.d(TAG, "url_bars in compat mode: " + Arrays.toString(urlBarIds)); + } + if (urlBarIds != null) { + Helper.sanitizeUrlBar(structure, urlBarIds); } } structure.sanitizeForParceling(true); @@ -1436,11 +1438,25 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final AutofillValue filledValue = viewState.getAutofilledValue(); if (!value.equals(filledValue)) { - if (sDebug) { - Slog.d(TAG, "found a change on required " + id + ": " + filledValue - + " => " + value); + boolean changed = true; + if (filledValue == null) { + // Dataset was not autofilled, make sure initial value didn't change. + final AutofillValue initialValue = getValueFromContextsLocked(id); + if (initialValue != null && initialValue.equals(value)) { + if (sDebug) { + Slog.d(TAG, "id " + id + " is part of dataset but initial value " + + "didn't change: " + value); + } + changed = false; + } + } + if (changed) { + if (sDebug) { + Slog.d(TAG, "found a change on required " + id + ": " + filledValue + + " => " + value); + } + atLeastOneChanged = true; } - atLeastOneChanged = true; } } } @@ -1872,7 +1888,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL); mViewStates.put(id, viewState); - // TODO(b/70407264): for optimization purposes, should also ignore if change is + // TODO(b/73648631): for optimization purposes, should also ignore if change is // detectable, and batch-send them when the session is finished (but that will // require tracking detectable fields on AutofillManager) if (isIgnored) { diff --git a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java new file mode 100644 index 0000000000000000000000000000000000000000..4de2c9b8e79f4af316c04aa9c444d7f4fbacd814 --- /dev/null +++ b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java @@ -0,0 +1,150 @@ +/* + * 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 com.android.server.backup; + +import android.content.ContentResolver; +import android.os.Handler; +import android.provider.Settings; +import android.util.KeyValueListParser; +import android.util.KeyValueSettingObserver; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + +/** + * Configure backup and restore agent timeouts. + * + *

    These timeout parameters are stored in Settings.Global to be configurable flags with P/H. They + * are represented as a comma-delimited key value list. + */ +public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { + @VisibleForTesting + public static final String SETTING = Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS; + + @VisibleForTesting + public static final String SETTING_KV_BACKUP_AGENT_TIMEOUT_MILLIS = + "kv_backup_agent_timeout_millis"; + + @VisibleForTesting + public static final String SETTING_FULL_BACKUP_AGENT_TIMEOUT_MILLIS = + "full_backup_agent_timeout_millis"; + + @VisibleForTesting + public static final String SETTING_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS = + "shared_backup_agent_timeout_millis"; + + @VisibleForTesting + public static final String SETTING_RESTORE_AGENT_TIMEOUT_MILLIS = + "restore_agent_timeout_millis"; + + @VisibleForTesting + public static final String SETTING_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS = + "restore_agent_finished_timeout_millis"; + + // Default values + @VisibleForTesting public static final long DEFAULT_KV_BACKUP_AGENT_TIMEOUT_MILLIS = 30 * 1000; + + @VisibleForTesting + public static final long DEFAULT_FULL_BACKUP_AGENT_TIMEOUT_MILLIS = 5 * 60 * 1000; + + @VisibleForTesting + public static final long DEFAULT_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS = 30 * 60 * 1000; + + @VisibleForTesting public static final long DEFAULT_RESTORE_AGENT_TIMEOUT_MILLIS = 60 * 1000; + + @VisibleForTesting + public static final long DEFAULT_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS = 30 * 1000; + + @GuardedBy("mLock") + private long mKvBackupAgentTimeoutMillis; + + @GuardedBy("mLock") + private long mFullBackupAgentTimeoutMillis; + + @GuardedBy("mLock") + private long mSharedBackupAgentTimeoutMillis; + + @GuardedBy("mLock") + private long mRestoreAgentTimeoutMillis; + + @GuardedBy("mLock") + private long mRestoreAgentFinishedTimeoutMillis; + + private final Object mLock = new Object(); + + public BackupAgentTimeoutParameters(Handler handler, ContentResolver resolver) { + super(handler, resolver, Settings.Global.getUriFor(SETTING)); + } + + public String getSettingValue(ContentResolver resolver) { + return Settings.Global.getString(resolver, SETTING); + } + + public void update(KeyValueListParser parser) { + synchronized (mLock) { + mKvBackupAgentTimeoutMillis = + parser.getLong( + SETTING_KV_BACKUP_AGENT_TIMEOUT_MILLIS, + DEFAULT_KV_BACKUP_AGENT_TIMEOUT_MILLIS); + mFullBackupAgentTimeoutMillis = + parser.getLong( + SETTING_FULL_BACKUP_AGENT_TIMEOUT_MILLIS, + DEFAULT_FULL_BACKUP_AGENT_TIMEOUT_MILLIS); + mSharedBackupAgentTimeoutMillis = + parser.getLong( + SETTING_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS, + DEFAULT_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS); + mRestoreAgentTimeoutMillis = + parser.getLong( + SETTING_RESTORE_AGENT_TIMEOUT_MILLIS, + DEFAULT_RESTORE_AGENT_TIMEOUT_MILLIS); + mRestoreAgentFinishedTimeoutMillis = + parser.getLong( + SETTING_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS, + DEFAULT_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS); + } + } + + public long getKvBackupAgentTimeoutMillis() { + synchronized (mLock) { + return mKvBackupAgentTimeoutMillis; + } + } + + public long getFullBackupAgentTimeoutMillis() { + synchronized (mLock) { + return mFullBackupAgentTimeoutMillis; + } + } + + public long getSharedBackupAgentTimeoutMillis() { + synchronized (mLock) { + return mSharedBackupAgentTimeoutMillis; + } + } + + public long getRestoreAgentTimeoutMillis() { + synchronized (mLock) { + return mRestoreAgentTimeoutMillis; + } + } + + public long getRestoreAgentFinishedTimeoutMillis() { + synchronized (mLock) { + return mRestoreAgentFinishedTimeoutMillis; + } + } +} diff --git a/services/backup/java/com/android/server/backup/BackupManagerConstants.java b/services/backup/java/com/android/server/backup/BackupManagerConstants.java index 99160c24d3b49b224d68459b9037a11e13c1b209..dd6e6ab2ece1929f7c47fdc35729f040028b070f 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. + *

    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 369df540581a5e4d087e0f1a387afa3a1e904599..d6f6c6cf1fc3a94466074ecd5fb8f227fad45c38 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 allAgentPackages() { // !!! TODO: cache this and regenerate only when necessary - int flags = PackageManager.GET_SIGNATURES; + int flags = PackageManager.GET_SIGNING_CERTIFICATES; List 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; @@ -3525,7 +3530,10 @@ public class BackupManagerService implements BackupManagerServiceInterface { dumpAgents(pw); return; } else if ("transportclients".equals(arg.toLowerCase())) { - mTransportManager.dump(pw); + mTransportManager.dumpTransportClients(pw); + return; + } else if ("transportstats".equals(arg.toLowerCase())) { + mTransportManager.dumpTransportStats(pw); return; } } @@ -3590,7 +3598,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { } } - mTransportManager.dump(pw); + mTransportManager.dumpTransportClients(pw); pw.println("Pending init: " + mPendingInits.size()); for (String s : mPendingInits) { diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java index 3cf374faada4c18d15ac01d39bf58ae4fc4e0226..dc28cd179bcba72918d261be96cc21416cd4adac 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 getStorableApplications(PackageManager pm) { List 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/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java index c87d2987d0b252228fc447bc8c8a104227a5cd14..6a1bf178ad6034ccd79edabaa534b6ae6565daca 100644 --- a/services/backup/java/com/android/server/backup/TransportManager.java +++ b/services/backup/java/com/android/server/backup/TransportManager.java @@ -44,6 +44,7 @@ import com.android.server.backup.transport.TransportClientManager; import com.android.server.backup.transport.TransportConnectionListener; import com.android.server.backup.transport.TransportNotAvailableException; import com.android.server.backup.transport.TransportNotRegisteredException; +import com.android.server.backup.transport.TransportStats; import java.io.PrintWriter; import java.util.List; @@ -64,6 +65,7 @@ public class TransportManager { private final PackageManager mPackageManager; private final Set mTransportWhitelist; private final TransportClientManager mTransportClientManager; + private final TransportStats mTransportStats; private OnTransportRegisteredListener mOnTransportRegisteredListener = (c, n) -> {}; /** @@ -85,7 +87,12 @@ public class TransportManager { private volatile String mCurrentTransportName; TransportManager(Context context, Set whitelist, String selectedTransport) { - this(context, whitelist, selectedTransport, new TransportClientManager(context)); + mContext = context; + mPackageManager = context.getPackageManager(); + mTransportWhitelist = Preconditions.checkNotNull(whitelist); + mCurrentTransportName = selectedTransport; + mTransportStats = new TransportStats(); + mTransportClientManager = new TransportClientManager(context, mTransportStats); } @VisibleForTesting @@ -98,6 +105,7 @@ public class TransportManager { mPackageManager = context.getPackageManager(); mTransportWhitelist = Preconditions.checkNotNull(whitelist); mCurrentTransportName = selectedTransport; + mTransportStats = new TransportStats(); mTransportClientManager = transportClientManager; } @@ -640,10 +648,14 @@ public class TransportManager { !Thread.holdsLock(mTransportLock), "Can't call transport with transport lock held"); } - public void dump(PrintWriter pw) { + public void dumpTransportClients(PrintWriter pw) { mTransportClientManager.dump(pw); } + public void dumpTransportStats(PrintWriter pw) { + mTransportStats.dump(pw); + } + private static Predicate fromPackageFilter(String packageName) { return transportComponent -> packageName.equals(transportComponent.getPackageName()); } 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 2e2d3eb4ad214100eb864a774d3c972340d39417..821cca16bf607eede116dabc67cb88231aed19b3 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 allPackages = pm.getInstalledPackages(PackageManager.GET_SIGNATURES); + List 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 f9c366998ad22e7a0087cb34707b29a17563c1ff..2c2dd8528cb11810a06ba979a4ed0c22fad0dd02 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 0ba83cfeb36193ac37f7ebd9f7d00692a5adfb18..11394e66a0f0ee3199fdf0617fd3b98990e5e701 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 0ca4f25093ce68497689e16f84e6888ff1c46148..c1a1c1dc10e7c884298592cef2f70d3faa9f6c5c 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 e576b3c32859042a0fa53ca1672a064124c4f09c..dacde0b9af6801e8d262a7454dad20080c7be2dc 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 3caa1e7fab796efa5b0a60746df77a365d5ef2f2..4b467e5a0399cc2a64bbab8e586df02f4fbcc818 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/transport/TransportClient.java b/services/backup/java/com/android/server/backup/transport/TransportClient.java index 1a2ca923229d5399d39402d4211dcad4184a03ff..fa881a97d4202a8b8cfe5e49ae5c2eb1762bd368 100644 --- a/services/backup/java/com/android/server/backup/transport/TransportClient.java +++ b/services/backup/java/com/android/server/backup/transport/TransportClient.java @@ -29,6 +29,7 @@ import android.os.DeadObjectException; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.SystemClock; import android.os.UserHandle; import android.text.format.DateFormat; import android.util.ArrayMap; @@ -51,6 +52,7 @@ import java.lang.ref.WeakReference; import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -78,6 +80,7 @@ public class TransportClient { private static final int LOG_BUFFER_SIZE = 5; private final Context mContext; + private final TransportStats mTransportStats; private final Intent mBindIntent; private final ServiceConnection mConnection; private final String mIdentifier; @@ -104,12 +107,14 @@ public class TransportClient { TransportClient( Context context, + TransportStats transportStats, Intent bindIntent, ComponentName transportComponent, String identifier, String caller) { this( context, + transportStats, bindIntent, transportComponent, identifier, @@ -120,12 +125,14 @@ public class TransportClient { @VisibleForTesting TransportClient( Context context, + TransportStats transportStats, Intent bindIntent, ComponentName transportComponent, String identifier, String caller, Handler listenerHandler) { mContext = context; + mTransportStats = transportStats; mTransportComponent = transportComponent; mBindIntent = bindIntent; mIdentifier = identifier; @@ -321,11 +328,16 @@ public class TransportClient { (requestedTransport, transportClient) -> transportFuture.complete(requestedTransport); + long requestTime = SystemClock.elapsedRealtime(); log(Priority.DEBUG, caller, "Sync connect: calling async"); connectAsync(requestListener, caller); try { - return transportFuture.get(); + transport = transportFuture.get(); + long time = SystemClock.elapsedRealtime() - requestTime; + mTransportStats.registerConnectionTime(mTransportComponent, time); + log(Priority.DEBUG, caller, String.format(Locale.US, "Connect took %d ms", time)); + return transport; } catch (InterruptedException | ExecutionException e) { String error = e.getClass().getSimpleName(); log(Priority.ERROR, caller, error + " while waiting for transport: " + e.getMessage()); diff --git a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java index 96e7d2f536103a8eb367cbfeabf669ea1193ccf3..f4e39287b2771de468bbbcc10b13de38bc787e76 100644 --- a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java +++ b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java @@ -37,12 +37,14 @@ public class TransportClientManager { private static final String TAG = "TransportClientManager"; private final Context mContext; + private final TransportStats mTransportStats; private final Object mTransportClientsLock = new Object(); private int mTransportClientsCreated = 0; private Map mTransportClientsCallerMap = new WeakHashMap<>(); - public TransportClientManager(Context context) { + public TransportClientManager(Context context, TransportStats transportStats) { mContext = context; + mTransportStats = transportStats; } /** @@ -88,6 +90,7 @@ public class TransportClientManager { TransportClient transportClient = new TransportClient( mContext, + mTransportStats, bindIntent, transportComponent, Integer.toString(mTransportClientsCreated), diff --git a/services/backup/java/com/android/server/backup/transport/TransportStats.java b/services/backup/java/com/android/server/backup/transport/TransportStats.java new file mode 100644 index 0000000000000000000000000000000000000000..bd84782122ad5f9ee4c232ada7045796208b86b6 --- /dev/null +++ b/services/backup/java/com/android/server/backup/transport/TransportStats.java @@ -0,0 +1,122 @@ +/* + * 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 com.android.server.backup.transport; + +import android.annotation.Nullable; +import android.content.ComponentName; + +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +/** Responsible for aggregating {@link TransportClient} relevant times. */ +public class TransportStats { + private final Object mStatsLock = new Object(); + private final Map mTransportStats = new HashMap<>(); + + void registerConnectionTime(ComponentName transportComponent, long timeMs) { + synchronized (mStatsLock) { + Stats stats = mTransportStats.get(transportComponent); + if (stats == null) { + stats = new Stats(); + mTransportStats.put(transportComponent, stats); + } + stats.register(timeMs); + } + } + + /** Returns {@link Stats} for transport whose host service is {@code transportComponent}. */ + @Nullable + public Stats getStatsForTransport(ComponentName transportComponent) { + synchronized (mStatsLock) { + Stats stats = mTransportStats.get(transportComponent); + if (stats == null) { + return null; + } + return new Stats(stats); + } + } + + public void dump(PrintWriter pw) { + synchronized (mStatsLock) { + Optional aggregatedStats = + mTransportStats.values().stream().reduce(Stats::merge); + if (aggregatedStats.isPresent()) { + dumpStats(pw, "", aggregatedStats.get()); + } + if (!mTransportStats.isEmpty()) { + pw.println("Per transport:"); + for (ComponentName transportComponent : mTransportStats.keySet()) { + Stats stats = mTransportStats.get(transportComponent); + pw.println(" " + transportComponent.flattenToShortString()); + dumpStats(pw, " ", stats); + } + } + } + } + + private static void dumpStats(PrintWriter pw, String prefix, Stats stats) { + pw.println( + String.format( + Locale.US, "%sAverage connection time: %.2f ms", prefix, stats.average)); + pw.println(String.format(Locale.US, "%sMax connection time: %d ms", prefix, stats.max)); + pw.println(String.format(Locale.US, "%sMin connection time: %d ms", prefix, stats.min)); + pw.println(String.format(Locale.US, "%sNumber of connections: %d ", prefix, stats.n)); + } + + public static final class Stats { + public static Stats merge(Stats a, Stats b) { + return new Stats( + a.n + b.n, + (a.average * a.n + b.average * b.n) / (a.n + b.n), + Math.max(a.max, b.max), + Math.min(a.min, b.min)); + } + + public int n; + public double average; + public long max; + public long min; + + public Stats() { + n = 0; + average = 0; + max = 0; + min = Long.MAX_VALUE; + } + + private Stats(int n, double average, long max, long min) { + this.n = n; + this.average = average; + this.max = max; + this.min = min; + } + + private Stats(Stats original) { + this(original.n, original.average, original.max, original.min); + } + + private void register(long sample) { + average = (average * n + sample) / (n + 1); + n++; + max = Math.max(max, sample); + min = Math.min(min, sample); + } + } +} 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 6780563120e35cb97571f02ea39aab094cccf1b4..5518374ebdbca399c905f09f1865ff0f68cdf376 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 { * *

      *
    • Source and target have at least one signature each - *
    • Target contains all signatures in source + *
    • Target contains all signatures in source, and nothing more *
    * + * 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 d2ab09996d680e9dc8e387357e54e0ea909947d8..994d5a967298bca505461264f7a7d58dcdfe8134 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 10f06954f17faa940b6f48ad7bb91db791da28b9..df7e6d45ba0fb6d5075d129b9d1e7e81803b1196 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 cc26ff8b50906e15762adc70d3ebf01483e1fdc6..6dd5284879f09963914a30ec5056ef209c898fe1 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 15f3a2362043dbe65098ec73b894a217a991eaa8..9756d17f662ede188aa44b8b90a39eba36ac3322 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 usageRestrictions = mAudioRestrictions.get(code); if (usageRestrictions == null) { @@ -1344,8 +1346,9 @@ public class AppOpsService extends IAppOpsService.Stub { return; } if (!client.mStartedOps.remove(op)) { - throw new IllegalStateException("Operation not started: uid" + op.uid + Slog.wtf(TAG, "Operation not started: uid" + op.uid + " pkg=" + op.packageName + " op=" + op.op); + return; } finishOperationLocked(op, /*finishNested*/ false); if (op.nesting <= 0) { @@ -2330,7 +2333,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 +2349,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/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java index 16be680b17709cb3c10bb8f88582e13b86cd84ed..6d773e6eb202b974dfa8fab2ace25ca89d289129 100644 --- a/services/core/java/com/android/server/AppStateTracker.java +++ b/services/core/java/com/android/server/AppStateTracker.java @@ -70,17 +70,12 @@ import java.util.List; * - Temporary power save whitelist * - Global "force all apps standby" mode enforced by battery saver. * - * TODO: Make it a LocalService. - * * Test: atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java */ public class AppStateTracker { - private static final String TAG = "ForceAppStandbyTracker"; - private static final boolean DEBUG = true; - - @GuardedBy("AppStateTracker.class") - private static AppStateTracker sInstance; + private static final String TAG = "AppStateTracker"; + private static final boolean DEBUG = false; private final Object mLock = new Object(); private final Context mContext; diff --git a/services/core/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java index e884de00c15ab5fcd187d63bb69f026e3aefa15c..8ea3dd64697e03969722e58cc3358a095d514772 100644 --- a/services/core/java/com/android/server/DiskStatsService.java +++ b/services/core/java/com/android/server/DiskStatsService.java @@ -171,8 +171,8 @@ public class DiskStatsService extends Binder { if (proto != null) { long freeSpaceToken = proto.start(DiskStatsServiceDumpProto.PARTITIONS_FREE_SPACE); proto.write(DiskStatsFreeSpaceProto.FOLDER, folderType); - proto.write(DiskStatsFreeSpaceProto.AVAILABLE_SPACE, avail * bsize / 1024); - proto.write(DiskStatsFreeSpaceProto.TOTAL_SPACE, total * bsize / 1024); + proto.write(DiskStatsFreeSpaceProto.AVAILABLE_SPACE_KB, avail * bsize / 1024); + proto.write(DiskStatsFreeSpaceProto.TOTAL_SPACE_KB, total * bsize / 1024); proto.end(freeSpaceToken); } else { pw.print(name); @@ -247,23 +247,23 @@ public class DiskStatsService extends Binder { JSONObject json = new JSONObject(jsonString); long cachedValuesToken = proto.start(DiskStatsServiceDumpProto.CACHED_FOLDER_SIZES); - proto.write(DiskStatsCachedValuesProto.AGG_APPS_SIZE, + proto.write(DiskStatsCachedValuesProto.AGG_APPS_SIZE_KB, json.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY)); - proto.write(DiskStatsCachedValuesProto.AGG_APPS_DATA_SIZE, + proto.write(DiskStatsCachedValuesProto.AGG_APPS_DATA_SIZE_KB, json.getLong(DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY)); - proto.write(DiskStatsCachedValuesProto.AGG_APPS_CACHE_SIZE, + proto.write(DiskStatsCachedValuesProto.AGG_APPS_CACHE_SIZE_KB, json.getLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY)); - proto.write(DiskStatsCachedValuesProto.PHOTOS_SIZE, + proto.write(DiskStatsCachedValuesProto.PHOTOS_SIZE_KB, json.getLong(DiskStatsFileLogger.PHOTOS_KEY)); - proto.write(DiskStatsCachedValuesProto.VIDEOS_SIZE, + proto.write(DiskStatsCachedValuesProto.VIDEOS_SIZE_KB, json.getLong(DiskStatsFileLogger.VIDEOS_KEY)); - proto.write(DiskStatsCachedValuesProto.AUDIO_SIZE, + proto.write(DiskStatsCachedValuesProto.AUDIO_SIZE_KB, json.getLong(DiskStatsFileLogger.AUDIO_KEY)); - proto.write(DiskStatsCachedValuesProto.DOWNLOADS_SIZE, + proto.write(DiskStatsCachedValuesProto.DOWNLOADS_SIZE_KB, json.getLong(DiskStatsFileLogger.DOWNLOADS_KEY)); - proto.write(DiskStatsCachedValuesProto.SYSTEM_SIZE, + proto.write(DiskStatsCachedValuesProto.SYSTEM_SIZE_KB, json.getLong(DiskStatsFileLogger.SYSTEM_KEY)); - proto.write(DiskStatsCachedValuesProto.OTHER_SIZE, + proto.write(DiskStatsCachedValuesProto.OTHER_SIZE_KB, json.getLong(DiskStatsFileLogger.MISC_KEY)); JSONArray packageNamesArray = json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY); @@ -279,9 +279,9 @@ public class DiskStatsService extends Binder { proto.write(DiskStatsAppSizesProto.PACKAGE_NAME, packageNamesArray.getString(i)); - proto.write(DiskStatsAppSizesProto.APP_SIZE, appSizesArray.getLong(i)); - proto.write(DiskStatsAppSizesProto.APP_DATA_SIZE, appDataSizesArray.getLong(i)); - proto.write(DiskStatsAppSizesProto.CACHE_SIZE, cacheSizesArray.getLong(i)); + proto.write(DiskStatsAppSizesProto.APP_SIZE_KB, appSizesArray.getLong(i)); + proto.write(DiskStatsAppSizesProto.APP_DATA_SIZE_KB, appDataSizesArray.getLong(i)); + proto.write(DiskStatsAppSizesProto.CACHE_SIZE_KB, cacheSizesArray.getLong(i)); proto.end(packageToken); } diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 70ca161167406e66741b27a637c52a7a00e6f7b5..5b57c14c11153e91edb8d0c8d64ff67fe5e6d746 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -92,7 +92,6 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.database.ContentObserver; import android.graphics.drawable.Drawable; -import android.hardware.input.InputManagerInternal; import android.inputmethodservice.InputMethodService; import android.net.Uri; import android.os.Binder; @@ -2490,16 +2489,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - private void notifyInputMethodSubtypeChanged(final int userId, - @Nullable final InputMethodInfo inputMethodInfo, - @Nullable final InputMethodSubtype subtype) { - final InputManagerInternal inputManagerInternal = - LocalServices.getService(InputManagerInternal.class); - if (inputManagerInternal != null) { - inputManagerInternal.onInputMethodSubtypeChanged(userId, inputMethodInfo, subtype); - } - } - /* package */ void setInputMethodLocked(String id, int subtypeId) { InputMethodInfo info = mMethodMap.get(id); if (info == null) { @@ -2534,10 +2523,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurMethod.changeInputMethodSubtype(newSubtype); } catch (RemoteException e) { Slog.w(TAG, "Failed to call changeInputMethodSubtype"); - return; } } - notifyInputMethodSubtypeChanged(mSettings.getCurrentUserId(), info, newSubtype); } return; } @@ -2563,9 +2550,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } finally { Binder.restoreCallingIdentity(ident); } - - notifyInputMethodSubtypeChanged(mSettings.getCurrentUserId(), info, - getCurrentInputMethodSubtypeLocked()); } @Override diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 3927ebd593bd0bcfaddfb9ad00c0a689dc1bedb6..539c00135f6a1469fb780b580f2c2ee0cdadd792 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; @@ -90,6 +89,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private static final boolean VDBG = false; // STOPSHIP if true private static class Record { + Context context; + String callingPackage; IBinder binder; @@ -108,8 +109,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { int phoneId = SubscriptionManager.INVALID_PHONE_INDEX; - boolean canReadPhoneState; - boolean matchPhoneStateListenerEvent(int events) { return (callback != null) && ((events & this.events) != 0); } @@ -118,6 +117,15 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { return (onSubscriptionsChangedListenerCallback != null); } + boolean canReadPhoneState() { + try { + return TelephonyPermissions.checkReadPhoneState( + context, subId, callerPid, callerUid, callingPackage, "listen"); + } catch (SecurityException e) { + return false; + } + } + @Override public String toString() { return "{callingPackage=" + callingPackage + " binder=" + binder @@ -125,8 +133,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { + " onSubscriptionsChangedListenererCallback=" + onSubscriptionsChangedListenerCallback + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId - + " events=" + Integer.toHexString(events) - + " canReadPhoneState=" + canReadPhoneState + "}"; + + " events=" + Integer.toHexString(events) + "}"; } } @@ -164,14 +171,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[] mConnectedApns; - - private LinkProperties[] mDataConnectionLinkProperties; - - private NetworkCapabilities[] mDataConnectionNetworkCapabilities; - private Bundle[] mCellLocation; private int[] mDataConnectionNetworkType; @@ -212,11 +214,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR | PhoneStateListener.LISTEN_VOLTE_STATE; - static final int CHECK_PHONE_STATE_PERMISSION_MASK = - PhoneStateListener.LISTEN_CALL_STATE | - PhoneStateListener.LISTEN_DATA_ACTIVITY | - PhoneStateListener.LISTEN_DATA_CONNECTION_STATE; - static final int PRECISE_PHONE_STATE_PERMISSION_MASK = PhoneStateListener.LISTEN_PRECISE_CALL_STATE | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE; @@ -323,9 +320,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 +335,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>(); mPhysicalChannelConfigs = new ArrayList>(); for (int i = 0; i < numPhones; i++) { @@ -358,7 +352,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mCellLocation[i] = new Bundle(); mCellInfo.add(i, null); mPhysicalChannelConfigs.add(i, null); - mConnectedApns[i] = new ArrayList(); } // Note that location can be null for non-phone builds like @@ -386,20 +379,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { public void addOnSubscriptionsChangedListener(String callingPackage, IOnSubscriptionsChangedListener callback) { int callerUserId = UserHandle.getCallingUserId(); - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); if (VDBG) { log("listen oscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId + " callback=" + callback + " callback.asBinder=" + callback.asBinder()); } - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( - mContext, callingPackage, "addOnSubscriptionsChangedListener")) { - return; - } - - synchronized (mRecords) { // register IBinder b = callback.asBinder(); @@ -409,12 +395,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } + r.context = mContext; r.onSubscriptionsChangedListenerCallback = callback; r.callingPackage = callingPackage; r.callerUid = Binder.getCallingUid(); r.callerPid = Binder.getCallingPid(); r.events = 0; - r.canReadPhoneState = true; // permission has been enforced above if (DBG) { log("listen oscl: Register r=" + r); } @@ -483,8 +469,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private void listen(String callingPackage, IPhoneStateListener callback, int events, boolean notifyNow, int subId) { int callerUserId = UserHandle.getCallingUserId(); - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); if (VDBG) { log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events) + " notifyNow=" + notifyNow + " subId=" + subId + " myUserId=" @@ -495,7 +480,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { // Checks permission and throws SecurityException for disallowed operations. For pre-M // apps whose runtime permission has been revoked, we return immediately to skip sending // events to the app without crashing it. - if (!checkListenerPermission(events, callingPackage, "listen")) { + if (!checkListenerPermission(events, subId, callingPackage, "listen")) { return; } @@ -509,14 +494,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } + r.context = mContext; r.callback = callback; r.callingPackage = callingPackage; r.callerUid = Binder.getCallingUid(); r.callerPid = Binder.getCallingPid(); - boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK - | ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0; - r.canReadPhoneState = - isPhoneStateEvent && canReadPhoneState(callingPackage, "listen"); // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID if (!SubscriptionManager.isValidSubscriptionId(subId)) { @@ -684,18 +666,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - private boolean canReadPhoneState(String callingPackage, String message) { - try { - return TelephonyPermissions.checkCallingOrSelfReadPhoneState( - mContext, callingPackage, message); - } catch (SecurityException e) { - return false; - } - } - private String getCallIncomingNumber(Record record, int phoneId) { - // Hide the number if record's process has no READ_PHONE_STATE permission - return record.canReadPhoneState ? mCallIncomingNumber[phoneId] : ""; + // Hide the number if record's process can't currently read phone state. + return record.canReadPhoneState() ? mCallIncomingNumber[phoneId] : ""; } private Record add(IBinder binder) { @@ -770,7 +743,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) && (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) { try { - String incomingNumberOrEmpty = r.canReadPhoneState ? incomingNumber : ""; + String incomingNumberOrEmpty = r.canReadPhoneState() ? incomingNumber : ""; r.callback.onCallStateChanged(state, incomingNumberOrEmpty); } catch (RemoteException ex) { mRemoveList.add(r.binder); @@ -1216,36 +1189,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) { @@ -1256,15 +1205,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, ""); @@ -1500,14 +1450,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); @@ -1724,7 +1670,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { == PackageManager.PERMISSION_GRANTED; } - private boolean checkListenerPermission(int events, String callingPackage, String message) { + private boolean checkListenerPermission( + int events, int subId, String callingPackage, String message) { if ((events & ENFORCE_COARSE_LOCATION_PERMISSION_MASK) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.ACCESS_COARSE_LOCATION, null); @@ -1736,7 +1683,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) { if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( - mContext, callingPackage, message)) { + mContext, subId, callingPackage, message)) { return false; } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index d2955369e7b0b4d38e75f6d899dd27affb75493f..cc0a7ae8a46458f529780b563e3df0ca900ab2f3 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -3459,10 +3459,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 8b799101b6bb6fe1fcc0ec8e5292d84d1a69c446..e6c4aaadc9d06807f6d1b337f5990a699e439223 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -110,6 +110,7 @@ import static android.os.Process.setThreadPriority; import static android.os.Process.setThreadScheduler; import static android.os.Process.startWebView; import static android.os.Process.zygoteProcess; +import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES; import static android.provider.Settings.Global.DEBUG_APP; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; @@ -186,6 +187,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMI import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY; import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; @@ -256,6 +258,7 @@ import android.app.RemoteAction; import android.app.WaitResult; import android.app.WindowConfiguration.ActivityType; import android.app.WindowConfiguration.WindowingMode; +import android.app.admin.DevicePolicyCache; import android.app.admin.DevicePolicyManager; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; @@ -748,6 +751,13 @@ public class ActivityManagerService extends IActivityManager.Stub */ private ActivityRecord mLastResumedActivity; + /** + * The activity that is currently being traced as the active resumed activity. + * + * @see #updateResumedAppTrace + */ + private @Nullable ActivityRecord mTracedResumedActivity; + /** * If non-null, we are tracking the time the user spends in the currently focused app. */ @@ -758,21 +768,6 @@ public class ActivityManagerService extends IActivityManager.Stub */ private final RecentTasks mRecentTasks; - /** - * For addAppTask: cached of the last activity component that was added. - */ - ComponentName mLastAddedTaskComponent; - - /** - * For addAppTask: cached of the last activity uid that was added. - */ - int mLastAddedTaskUid; - - /** - * For addAppTask: cached of the last ActivityInfo that was added. - */ - ActivityInfo mLastAddedTaskActivity; - /** * The package name of the DeviceOwner. This package is not permitted to have its data cleared. */ @@ -3472,6 +3467,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (mLastResumedActivity != null && r.userId != mLastResumedActivity.userId) { mUserController.sendForegroundProfileChanged(r.userId); } + updateResumedAppTrace(r); mLastResumedActivity = r; mWindowManager.setFocusedApp(r.appToken, true); @@ -3485,6 +3481,22 @@ public class ActivityManagerService extends IActivityManager.Stub reason); } + private void updateResumedAppTrace(@Nullable ActivityRecord resumed) { + if (mTracedResumedActivity != null) { + Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER, + constructResumedTraceName(mTracedResumedActivity.packageName), 0); + } + if (resumed != null) { + Trace.asyncTraceBegin(TRACE_TAG_ACTIVITY_MANAGER, + constructResumedTraceName(resumed.packageName), 0); + } + mTracedResumedActivity = resumed; + } + + private String constructResumedTraceName(String packageName) { + return "focused app: " + packageName; + } + @Override public void setFocusedStack(int stackId) { enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()"); @@ -5471,11 +5483,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); @@ -7646,6 +7659,9 @@ public class ActivityManagerService extends IActivityManager.Stub if (profilerInfo != null && profilerInfo.profileFd != null) { profilerInfo.profileFd = profilerInfo.profileFd.dup(); + if (TextUtils.equals(mProfileApp, processName) && mProfilerInfo != null) { + clearProfilerLocked(); + } } // We deprecated Build.SERIAL and it is not accessible to @@ -7730,7 +7746,10 @@ public class ActivityManagerService extends IActivityManager.Stub mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, isAutofillCompatEnabled); } - + if (profilerInfo != null) { + profilerInfo.closeFd(); + profilerInfo = null; + } checkTime(startTime, "attachApplicationLocked: immediately after bindApplication"); updateLruProcessLocked(app, false, null); checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked"); @@ -10688,27 +10707,24 @@ public class ActivityManagerService extends IActivityManager.Stub intent.addFlags(Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS); } } - if (!comp.equals(mLastAddedTaskComponent) || callingUid != mLastAddedTaskUid) { - mLastAddedTaskActivity = null; - } - ActivityInfo ainfo = mLastAddedTaskActivity; - if (ainfo == null) { - ainfo = mLastAddedTaskActivity = AppGlobals.getPackageManager().getActivityInfo( - comp, 0, UserHandle.getUserId(callingUid)); - if (ainfo.applicationInfo.uid != callingUid) { - throw new SecurityException( - "Can't add task for another application: target uid=" - + ainfo.applicationInfo.uid + ", calling uid=" + callingUid); - } + final ActivityInfo ainfo = AppGlobals.getPackageManager().getActivityInfo(comp, 0, + UserHandle.getUserId(callingUid)); + if (ainfo.applicationInfo.uid != callingUid) { + throw new SecurityException( + "Can't add task for another application: target uid=" + + ainfo.applicationInfo.uid + ", calling uid=" + callingUid); } - TaskRecord task = TaskRecord.create(this, - mStackSupervisor.getNextTaskIdForUserLocked(r.userId), - ainfo, intent, description); + final ActivityStack stack = r.getStack(); + final TaskRecord task = stack.createTaskRecord( + mStackSupervisor.getNextTaskIdForUserLocked(r.userId), ainfo, intent, + null /* voiceSession */, null /* voiceInteractor */, !ON_TOP); if (!mRecentTasks.addToBottom(task)) { + // The app has too many tasks already and we can't add any more + stack.removeTask(task, "addAppTask", REMOVE_TASK_MODE_DESTROYING); return INVALID_TASK_ID; } - r.getStack().addTask(task, !ON_TOP, "addAppTask"); + task.lastTaskDescription.copyFrom(description); // TODO: Send the thumbnail to WM to store it. @@ -13181,6 +13197,7 @@ public class ActivityManagerService extends IActivityManager.Stub } mTopProcessState = ActivityManager.PROCESS_STATE_TOP_SLEEPING; mStackSupervisor.goingToSleepLocked(); + updateResumedAppTrace(null /* resumed */); updateOomAdjLocked(); } } @@ -13836,9 +13853,7 @@ public class ActivityManagerService extends IActivityManager.Stub } userId = activity.userId; } - DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService( - Context.DEVICE_POLICY_SERVICE); - return (dpm == null) || (!dpm.getScreenCaptureDisabled(null, userId)); + return !DevicePolicyCache.getInstance().getScreenCaptureDisabled(userId); } @Override @@ -14366,14 +14381,20 @@ public class ActivityManagerService extends IActivityManager.Stub return err; } - synchronized(this) { - r.requestedVrComponent = (enabled) ? packageName : null; + // Clear the binder calling uid since this path may call moveToTask(). + final long callingId = Binder.clearCallingIdentity(); + try { + synchronized(this) { + r.requestedVrComponent = (enabled) ? packageName : null; - // Update associated state if this activity is currently focused - if (r == mStackSupervisor.getResumedActivityLocked()) { - applyUpdateVrModeLocked(r); + // Update associated state if this activity is currently focused + if (r == mStackSupervisor.getResumedActivityLocked()) { + applyUpdateVrModeLocked(r); + } + return 0; } - return 0; + } finally { + Binder.restoreCallingIdentity(callingId); } } @@ -25535,6 +25556,14 @@ public class ActivityManagerService extends IActivityManager.Stub } catch (IOException e) { } mProfilerInfo.profileFd = null; + + if (proc.pid == MY_PID) { + // When profiling the system server itself, avoid closing the file + // descriptor, as profilerControl will not create a copy. + // Note: it is also not correct to just set profileFd to null, as the + // whole ProfilerInfo instance is passed down! + profilerInfo = null; + } } else { stopProfilerLocked(proc, profileType); if (profilerInfo != null && profilerInfo.profileFd != null) { @@ -26082,16 +26111,19 @@ public class ActivityManagerService extends IActivityManager.Stub Bundle bOptions) { Preconditions.checkNotNull(intents, "intents"); final String[] resolvedTypes = new String[intents.length]; - for (int i = 0; i < intents.length; i++) { - resolvedTypes[i] = intents[i].resolveTypeIfNeeded(mContext.getContentResolver()); - } // UID of the package on user userId. // "= 0" is needed because otherwise catch(RemoteException) would make it look like // packageUid may not be initialized. int packageUid = 0; final long ident = Binder.clearCallingIdentity(); + try { + for (int i = 0; i < intents.length; i++) { + resolvedTypes[i] = + intents[i].resolveTypeIfNeeded(mContext.getContentResolver()); + } + packageUid = AppGlobals.getPackageManager().getPackageUid( packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId); } catch (RemoteException e) { @@ -26374,10 +26406,12 @@ public class ActivityManagerService extends IActivityManager.Stub return mUserController.mMaxRunningUsers; } + @Override public boolean isCallerRecents(int callingUid) { return getRecentTasks().isCallerRecents(callingUid); } + @Override public boolean isRecentsComponentHomeActivity(int userId) { return getRecentTasks().isRecentsComponentHomeActivity(userId); } @@ -26416,6 +26450,11 @@ public class ActivityManagerService extends IActivityManager.Stub } return processMemoryStates; } + + @Override + public void enforceCallerIsRecentsOrHasPermission(String permission, String func) { + ActivityManagerService.this.enforceCallerIsRecentsOrHasPermission(permission, func); + } } /** diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 352b75704d6e308ca53392cb402aa6ced881b858..724dd3fd984758aedc7f33d1c4b4f71d1597826a 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -299,7 +299,7 @@ class ActivityMetricsLogger { final boolean otherWindowModesLaunching = mWindowingModeTransitionInfo.size() > 0 && info == null; - if ((resultCode < 0 || launchedActivity == null || !processSwitch + if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) { // Failed to launch or it was not a process switch, so we don't care about the timing. @@ -321,6 +321,14 @@ class ActivityMetricsLogger { mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000); } + /** + * @return True if we should start logging an event for an activity start that returned + * {@code resultCode} and that we'll indeed get a windows drawn event. + */ + private boolean isLoggableResultCode(int resultCode) { + return resultCode == START_SUCCESS || resultCode == START_TASK_TO_FRONT; + } + /** * Notifies the tracker that all windows of the app have been drawn. */ diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index ded760f7bc9faaeb2dacc2b2a57e63086d01d5f3..768ab51d9aad3e0ce1d56728653ed15ae3534b58 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1196,6 +1196,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } boolean isFocusable() { + if (inSplitScreenPrimaryWindowingMode() && mStackSupervisor.mIsDockMinimized) { + return false; + } return getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable(); } @@ -1543,7 +1546,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType); break; } - pendingOptions = null; + + if (task == null) { + clearOptionsLocked(false /* withAbort */); + } else { + // This will clear the options for all the ActivityRecords for this Task. + task.clearAllPendingOptions(); + } } } @@ -1552,10 +1561,14 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } void clearOptionsLocked() { - if (pendingOptions != null) { + clearOptionsLocked(true /* withAbort */); + } + + void clearOptionsLocked(boolean withAbort) { + if (withAbort && pendingOptions != null) { pendingOptions.abort(); - pendingOptions = null; } + pendingOptions = null; } ActivityOptions takeOptionsLocked() { @@ -1624,12 +1637,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; @@ -1644,23 +1651,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() { @@ -1753,8 +1743,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // this when there is an activity waiting to become translucent as the extra binder // calls will lead to noticeable jank. A later call to // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to the proper - // paused state. - if (isState(STOPPED, STOPPING) && stack.mTranslucentActivityWaiting == null) { + // paused state. We also avoid doing this for the activity the stack supervisor + // considers the resumed activity, as normal means will bring the activity from STOPPED + // to RESUMED. Adding PAUSING in this scenario will lead to double lifecycles. + if (isState(STOPPED, STOPPING) && stack.mTranslucentActivityWaiting == null + && mStackSupervisor.getResumedActivityLocked() != this) { // Capture reason before state change final String reason = getLifecycleDescription("makeVisibleIfNeeded"); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 9a133dc0bd5c5e88276a31ab21aefbc790a71bbd..893a6d596411f6f7e49c9a21b26994dcc8e156c3 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -198,8 +198,12 @@ class ActivityStack extends ConfigurationContai // How long we wait for the activity to tell us it has stopped before // giving up. This is a good amount of time because we really need this - // from the application in order to get its saved state. - private static final int STOP_TIMEOUT = 10 * 1000; + // from the application in order to get its saved state. Once the stop + // is complete we may start destroying client resources triggering + // crashes if the UI thread was hung. We put this timeout one second behind + // the ANR timeout so these situations will generate ANR instead of + // Surface lost or other errors. + private static final int STOP_TIMEOUT = 11 * 1000; // How long we wait until giving up on an activity telling us it has // finished destroying itself. @@ -1357,17 +1361,7 @@ class ActivityStack extends ConfigurationContai if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING, "Sleep => pause with userLeaving=false"); - // If we are in the middle of resuming the top activity in - // {@link #resumeTopActivityUncheckedLocked}, mResumedActivity will be set but not - // resumed yet. We must not proceed pausing the activity here. This method will be - // called again if necessary as part of {@link #checkReadyForSleep} or - // {@link ActivityStackSupervisor#checkReadyForSleepLocked}. - if (mStackSupervisor.inResumeTopActivity) { - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "In the middle of resuming top activity " - + mResumedActivity); - } else { - startPausingLocked(false, true, null, false); - } + startPausingLocked(false, true, null, false); shouldSleep = false ; } else if (mPausingActivity != null) { // Still waiting for something to pause; can't sleep yet. @@ -2734,9 +2728,12 @@ class ActivityStack 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; @@ -3446,7 +3443,7 @@ class ActivityStack extends ConfigurationContai } /** Find next proper focusable stack and make it focused. */ - private boolean adjustFocusToNextFocusableStack(String reason) { + boolean adjustFocusToNextFocusableStack(String reason) { return adjustFocusToNextFocusableStack(reason, false /* allowFocusSelf */); } @@ -3851,14 +3848,6 @@ class ActivityStack 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() @@ -4077,26 +4066,16 @@ class ActivityStack 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; } @@ -4311,7 +4290,7 @@ class ActivityStack 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; } @@ -4322,8 +4301,7 @@ class ActivityStack extends ConfigurationContai boolean removedFromHistory = false; - cleanUpActivityLocked(r, false /* cleanServices */, false /* destroy */, - false /*clearProcess*/); + cleanUpActivityLocked(r, false, false); final boolean hadApp = r.app != null; @@ -4420,6 +4398,10 @@ class ActivityStack 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); @@ -4429,8 +4411,7 @@ class ActivityStack 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); } } @@ -4539,8 +4520,7 @@ class ActivityStack extends ConfigurationContai r.icicle = null; } } - cleanUpActivityLocked(r, true /* cleanServices */, remove /* destroy */, - true /*clearProcess*/); + cleanUpActivityLocked(r, true, true); if (remove) { removeActivityFromHistoryLocked(r, "appDied"); } @@ -5336,6 +5316,14 @@ class ActivityStack extends ConfigurationContai boolean shouldSleepActivities() { final ActivityDisplay display = getDisplay(); + + // Do not sleep activities in this stack if we're marked as focused and the keyguard + // is in the process of going away. + if (mStackSupervisor.getFocusedStack() == this + && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()) { + return false; + } + return display != null ? display.isSleeping() : mService.isSleepingLocked(); } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 95b64d1c3fadf983f4df511fb8ac43c2ff60a291..63035d72c060eac783428a415579f3945ea43373 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2471,19 +2471,20 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) { - // If the currently focused stack is in split-screen secondary we would prefer - // the focus to move to another split-screen secondary stack or fullscreen stack - // over the primary split screen stack to avoid: - // - Moving the focus to the primary split-screen stack when it can't be focused - // because it will be minimized, but AM doesn't know that yet - // - primary split-screen stack overlapping with a fullscreen stack when a - // fullscreen stack is higher in z than the next split-screen stack. Assistant - // stack, I am looking at you... + // If the currently focused stack is in split-screen secondary we save off the + // top primary split-screen stack as a candidate for focus because we might + // prefer focus to move to an other stack to avoid primary split-screen stack + // overlapping with a fullscreen stack when a fullscreen stack is higher in z + // than the next split-screen stack. Assistant stack, I am looking at you... // We only move the focus to the primary-split screen stack if there isn't a // better alternative. candidate = stack; continue; } + if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) { + // Use the candidate stack since we are now at the secondary split-screen. + return candidate; + } return stack; } } @@ -3419,10 +3420,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } else { stack.awakeFromSleepingLocked(); if (isFocusedStack(stack) - && !mKeyguardController.isKeyguardActive(display.mDisplayId)) { - // If there is no keyguard on this display - resume immediately. Otherwise - // we'll wait for keyguard visibility callback and resume while ensuring - // activities visibility + && !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 + // is released. As a result, it is important we resume the activity here. resumeFocusedStackTopActivityLocked(); } } @@ -4465,6 +4467,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void setDockedStackMinimized(boolean minimized) { mIsDockMinimized = minimized; + if (mIsDockMinimized) { + final ActivityStack current = getFocusedStack(); + if (current.inSplitScreenPrimaryWindowingMode()) { + // The primary split-screen stack can't be focused while it is minimize, so move + // focus to something else. + current.adjustFocusToNextFocusableStack("setDockedStackMinimized"); + } + } } void wakeUp(String reason) { diff --git a/services/core/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java index 7b3859789d2893f635764c45b8962b19e2fb2406..972a692d276fec678217fb034a09946283fca319 100644 --- a/services/core/java/com/android/server/am/AppBindRecord.java +++ b/services/core/java/com/android/server/am/AppBindRecord.java @@ -66,14 +66,13 @@ final class AppBindRecord { void writeToProto(ProtoOutputStream proto, long fieldId) { long token = proto.start(fieldId); - proto.write(AppBindRecordProto.HEX_HASH, - Integer.toHexString(System.identityHashCode(this))); - if (client != null) { - client.writeToProto(proto, AppBindRecordProto.CLIENT); - } + proto.write(AppBindRecordProto.SERVICE_NAME, service.shortName); + proto.write(AppBindRecordProto.CLIENT_PROC_NAME, client.processName); final int N = connections.size(); for (int i=0; i: optional name of package to filter output by."); pw.println(" -h: print this help text."); pw.println("Battery stats (batterystats) commands:"); @@ -1211,6 +1212,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } + private void dumpCpuStats(PrintWriter pw) { + synchronized (mStats) { + mStats.dumpCpuStatsLocked(pw); + } + } + private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) { i++; if (i >= args.length) { @@ -1324,6 +1331,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub } else if ("--settings".equals(arg)) { dumpSettings(pw); return; + } else if ("--cpu".equals(arg)) { + dumpCpuStats(pw); + return; } else if ("-a".equals(arg)) { flags |= BatteryStats.DUMP_VERBOSE; } else if (arg.length() > 0 && arg.charAt(0) == '-'){ diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index ea90db3f59686972725373e96f9c94f6ec1dba70..9a7634edd81ba28f6ee140ef0143561fc5fb8502 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -1457,10 +1457,17 @@ public final class BroadcastQueue { return; } - Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r. receiver + // If the receiver app is being debugged we quietly ignore unresponsiveness, just + // tidying up and moving on to the next broadcast without crashing or ANRing this + // app just because it's stopped at a breakpoint. + final boolean debugging = (r.curApp != null && r.curApp.debugging); + + Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver + ", started " + (now - r.receiverTime) + "ms ago"); r.receiverTime = now; - r.anrCount++; + if (!debugging) { + r.anrCount++; + } ProcessRecord app = null; String anrMessage = null; @@ -1500,7 +1507,7 @@ public final class BroadcastQueue { r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); - if (anrMessage != null) { + if (!debugging && anrMessage != null) { // Post the ANR to the handler since we do not want to process ANRs while // potentially holding our lock. mHandler.post(new AppNotResponding(app, anrMessage)); diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java index d320fb1d05609efdbe812e3c41cafa3e8ead2b0c..a8e9ad9ce87b713049d7a190c1ee083fe31ae01f 100644 --- a/services/core/java/com/android/server/am/ConnectionRecord.java +++ b/services/core/java/com/android/server/am/ConnectionRecord.java @@ -176,10 +176,6 @@ final class ConnectionRecord { if (binding.service != null) { proto.write(ConnectionRecordProto.SERVICE_NAME, binding.service.shortName); } - if (conn != null) { - proto.write(ConnectionRecordProto.CONN_HEX_HASH, - Integer.toHexString(System.identityHashCode(conn.asBinder()))); - } proto.end(token); } } diff --git a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java index d7d18a99b66fead8e81ee44379e65aeeeff19de5..5bf5020c99ee267ef87d5df21a741f8a0f31f4df 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, "sys.traced.enable_override"}, }; diff --git a/services/core/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java index 01ce64c6e0378b58c8f5d19d5a850be67864e60f..3457a809828433ab05d3ae72e08583d2039af137 100644 --- a/services/core/java/com/android/server/am/IntentBindRecord.java +++ b/services/core/java/com/android/server/am/IntentBindRecord.java @@ -113,10 +113,6 @@ final class IntentBindRecord { public void writeToProto(ProtoOutputStream proto, long fieldId) { long token = proto.start(fieldId); - proto.write(IntentBindRecordProto.HEX_HASH, - Integer.toHexString(System.identityHashCode(this))); - proto.write(IntentBindRecordProto.IS_CREATE, - (collectFlags()&Context.BIND_AUTO_CREATE) != 0); if (intent != null) { intent.getIntent().writeToProto(proto, IntentBindRecordProto.INTENT, false, true, false, false); @@ -124,6 +120,8 @@ final class IntentBindRecord { if (binder != null) { proto.write(IntentBindRecordProto.BINDER, binder.toString()); } + proto.write(IntentBindRecordProto.AUTO_CREATE, + (collectFlags()&Context.BIND_AUTO_CREATE) != 0); proto.write(IntentBindRecordProto.REQUESTED, requested); proto.write(IntentBindRecordProto.RECEIVED, received); proto.write(IntentBindRecordProto.HAS_BOUND, hasBound); diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java index 6b8b38073998d672a5f5bae5fae442212a86ab8c..0d7eab626ff00a847cb9fa02fbf9638a44d34b2a 100644 --- a/services/core/java/com/android/server/am/KeyguardController.java +++ b/services/core/java/com/android/server/am/KeyguardController.java @@ -86,23 +86,23 @@ class KeyguardController { * display, false otherwise */ boolean isKeyguardShowing(int displayId) { - return isKeyguardActive(displayId) && !mKeyguardGoingAway; + return mKeyguardShowing && !mKeyguardGoingAway && + (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing); } /** - * @return true if Keyguard is showing and not occluded. We ignore whether it is going away or - * not here. + * @return true if Keyguard is either showing or occluded, but not going away */ - boolean isKeyguardActive(int displayId) { - return mKeyguardShowing && (displayId == DEFAULT_DISPLAY ? !mOccluded - : displayId == mSecondaryDisplayShowing); + boolean isKeyguardLocked() { + return mKeyguardShowing && !mKeyguardGoingAway; } /** - * @return true if Keyguard is either showing or occluded, but not going away + * @return {@code true} if the keyguard is going away, {@code false} otherwise. */ - boolean isKeyguardLocked() { - return mKeyguardShowing && !mKeyguardGoingAway; + boolean isKeyguardGoingAway() { + // Also check keyguard showing in case value is stale. + return mKeyguardGoingAway && mKeyguardShowing; } /** diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java index af99111e4bfad745c5cf64e15cb195c23dd37890..ed39329844ef4b9bb6d8e3c325a2ec3fb033871d 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 f1b3dfa5c0034a81de2650e712a6f534d048cd02..fc8b624f6b7e6af6afa13b8e1e70ab65a5afa0fa 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -285,7 +285,7 @@ class RecentTasks { boolean isRecentsComponentHomeActivity(int userId) { final ComponentName defaultHomeActivity = mService.getPackageManagerInternalLocked() .getDefaultHomeActivity(userId); - return defaultHomeActivity != null && + return defaultHomeActivity != null && mRecentsComponent != null && defaultHomeActivity.getPackageName().equals(mRecentsComponent.getPackageName()); } @@ -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/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java index 91215685f35f3163df5d491eebfe7febd994a491..da56ffd57bf3ba4b249d2cda5b9174fa042b9d7e 100644 --- a/services/core/java/com/android/server/am/RecentsAnimation.java +++ b/services/core/java/com/android/server/am/RecentsAnimation.java @@ -16,6 +16,7 @@ package com.android.server.am; +import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; @@ -95,6 +96,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks { } } + mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(); + mService.setRunningRemoteAnimation(mCallingPid, true); mWindowManager.deferSurfaceLayout(); @@ -143,6 +146,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // If we updated the launch-behind state, update the visibility of the activities after // we fetch the visible tasks to be controlled by the animation mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS); + + mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(START_TASK_TO_FRONT, + homeActivity); } finally { mWindowManager.continueSurfaceLayout(); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index b6eff003d26e9238708b3cbad28997b1133d238b..49a55cbf8e9845fb2b4b3a16738775d1cf11c278 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -164,21 +164,20 @@ final class ServiceRecord extends Binder { public void writeToProto(ProtoOutputStream proto, long fieldId, long now) { long token = proto.start(fieldId); - proto.write(ServiceRecordProto.StartItemProto.ID, id); + proto.write(ServiceRecordProto.StartItem.ID, id); ProtoUtils.toDuration(proto, - ServiceRecordProto.StartItemProto.DURATION, deliveredTime, now); - proto.write(ServiceRecordProto.StartItemProto.DELIVERY_COUNT, deliveryCount); - proto.write(ServiceRecordProto.StartItemProto.DONE_EXECUTING_COUNT, doneExecutingCount); + ServiceRecordProto.StartItem.DURATION, deliveredTime, now); + proto.write(ServiceRecordProto.StartItem.DELIVERY_COUNT, deliveryCount); + proto.write(ServiceRecordProto.StartItem.DONE_EXECUTING_COUNT, doneExecutingCount); if (intent != null) { - intent.writeToProto(proto, ServiceRecordProto.StartItemProto.INTENT, true, true, + intent.writeToProto(proto, ServiceRecordProto.StartItem.INTENT, true, true, true, false); } if (neededGrants != null) { - neededGrants.writeToProto(proto, ServiceRecordProto.StartItemProto.NEEDED_GRANTS); + neededGrants.writeToProto(proto, ServiceRecordProto.StartItem.NEEDED_GRANTS); } if (uriPermissions != null) { - uriPermissions.writeToProto(proto, - ServiceRecordProto.StartItemProto.URI_PERMISSIONS); + uriPermissions.writeToProto(proto, ServiceRecordProto.StartItem.URI_PERMISSIONS); } proto.end(token); } @@ -236,8 +235,6 @@ final class ServiceRecord extends Binder { void writeToProto(ProtoOutputStream proto, long fieldId) { long token = proto.start(fieldId); proto.write(ServiceRecordProto.SHORT_NAME, this.shortName); - proto.write(ServiceRecordProto.HEX_HASH, - Integer.toHexString(System.identityHashCode(this))); proto.write(ServiceRecordProto.IS_RUNNING, app != null); if (app != null) { proto.write(ServiceRecordProto.PID, app.pid); diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 7280f57c628774715d59104330732bfea411b3d9..c7b89d3d47eba7d6f02976c61cc5e1262f096b71 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -944,7 +944,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } @Override - protected ConfigurationContainer getChildAt(int index) { + protected ActivityRecord getChildAt(int index) { return mActivities.get(index); } @@ -1898,6 +1898,12 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } } + void clearAllPendingOptions() { + for (int i = getChildCount() - 1; i >= 0; i--) { + getChildAt(i).clearOptionsLocked(false /* withAbort */); + } + } + void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("userId="); pw.print(userId); pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java index 3886e5a9f9657122c0083461767fe46c6c6b7857..d49f3baa7bcb39f4eef6bf3b1b20c65f6b6f3ee2 100644 --- a/services/core/java/com/android/server/am/UidRecord.java +++ b/services/core/java/com/android/server/am/UidRecord.java @@ -148,7 +148,6 @@ public final class UidRecord { void writeToProto(ProtoOutputStream proto, long fieldId) { long token = proto.start(fieldId); - proto.write(UidRecordProto.HEX_HASH, Integer.toHexString(System.identityHashCode(this))); proto.write(UidRecordProto.UID, uid); proto.write(UidRecordProto.CURRENT, ProcessList.makeProcStateProtoEnum(curProcState)); proto.write(UidRecordProto.EPHEMERAL, ephemeral); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index acd74da62ca1daacfa48bacb5e75c98ffdce5b99..35264444e04bfc78d376cef03da8fff6f853e09a 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -39,6 +39,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -256,6 +257,7 @@ public class AudioService extends IAudioService.Stub private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102; private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103; private static final int MSG_DISABLE_AUDIO_FOR_UID = 104; + private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105; // end of messages handled under wakelock private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; @@ -265,6 +267,8 @@ public class AudioService extends IAudioService.Stub // retry delay in case of failure to indicate system ready to AudioFlinger private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000; + private static final int BT_HEARING_AID_GAIN_MIN = -128; + /** @see AudioSystemThread */ private AudioSystemThread mAudioSystemThread; /** @see AudioHandler */ @@ -573,7 +577,7 @@ public class AudioService extends IAudioService.Stub AudioSystem.DEVICE_OUT_HDMI_ARC | AudioSystem.DEVICE_OUT_SPDIF | AudioSystem.DEVICE_OUT_AUX_LINE; - int mFullVolumeDevices = 0; + int mFullVolumeDevices = AudioSystem.DEVICE_OUT_HEARING_AID; private final boolean mMonitorRotation; @@ -590,6 +594,10 @@ public class AudioService extends IAudioService.Stub private final MediaFocusControl mMediaFocusControl; + // Reference to BluetoothA2dp to query for volume. + private BluetoothHearingAid mHearingAid; + // lock always taken synchronized on mConnectedDevices + private final Object mHearingAidLock = new Object(); // Reference to BluetoothA2dp to query for AbsoluteVolume. private BluetoothA2dp mA2dp; // lock always taken synchronized on mConnectedDevices @@ -719,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); @@ -849,6 +887,8 @@ public class AudioService extends IAudioService.Stub if (adapter != null) { adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, BluetoothProfile.A2DP); + adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, + BluetoothProfile.HEARING_AID); } if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) { @@ -1609,6 +1649,11 @@ public class AudioService extends IAudioService.Stub } } + // Check if volume update should be send to Hearing Aid + if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) { + setHearingAidVolume(newIndex); + } + // Check if volume update should be sent to Hdmi system audio. if (streamTypeAlias == AudioSystem.STREAM_MUSIC) { setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags); @@ -1854,6 +1899,10 @@ public class AudioService extends IAudioService.Stub } } + if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) { + setHearingAidVolume(index); + } + if (streamTypeAlias == AudioSystem.STREAM_MUSIC) { setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags); } @@ -3611,6 +3660,30 @@ public class AudioService extends IAudioService.Stub } break; + case BluetoothProfile.HEARING_AID: + synchronized (mConnectedDevices) { + synchronized (mHearingAidLock) { + mHearingAid = (BluetoothHearingAid) proxy; + deviceList = mHearingAid.getConnectedDevices(); + if (deviceList.size() > 0) { + btDevice = deviceList.get(0); + int state = mHearingAid.getConnectionState(btDevice); + int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0; + int delay = checkSendBecomingNoisyIntent( + AudioSystem.DEVICE_OUT_HEARING_AID, intState, + AudioSystem.DEVICE_NONE); + queueMsgUnderWakeLock(mAudioHandler, + MSG_SET_HEARING_AID_CONNECTION_STATE, + state, + 0 /* arg2 unused */, + btDevice, + delay); + } + } + } + + break; + default: break; } @@ -3630,6 +3703,10 @@ public class AudioService extends IAudioService.Stub disconnectHeadset(); break; + case BluetoothProfile.HEARING_AID: + disconnectHearingAid(); + break; + default: break; } @@ -3640,6 +3717,7 @@ public class AudioService extends IAudioService.Stub disconnectA2dp(); disconnectA2dpSink(); disconnectHeadset(); + disconnectHearingAid(); } void disconnectA2dp() { @@ -3691,6 +3769,29 @@ public class AudioService extends IAudioService.Stub } } + void disconnectHearingAid() { + synchronized (mConnectedDevices) { + synchronized (mHearingAidLock) { + ArraySet toRemove = null; + // Disconnect ALL DEVICE_OUT_HEARING_AID devices + for (int i = 0; i < mConnectedDevices.size(); i++) { + DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i); + if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) { + toRemove = toRemove != null ? toRemove : new ArraySet(); + toRemove.add(deviceSpec.mDeviceAddress); + } + } + if (toRemove != null) { + int delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_HEARING_AID, + 0, AudioSystem.DEVICE_NONE); + for (int i = 0; i < toRemove.size(); i++) { + makeHearingAidDeviceUnavailable(toRemove.valueAt(i) /*, delay*/); + } + } + } + } + } + private void onCheckMusicActive(String caller) { synchronized (mSafeMediaVolumeState) { if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) { @@ -4202,7 +4303,8 @@ public class AudioService extends IAudioService.Stub handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time); if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE || msg == MSG_SET_A2DP_SRC_CONNECTION_STATE || - msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) { + msg == MSG_SET_A2DP_SINK_CONNECTION_STATE || + msg == MSG_SET_HEARING_AID_CONNECTION_STATE) { mLastDeviceConnectMsgTime = time; } } @@ -4305,6 +4407,33 @@ public class AudioService extends IAudioService.Stub @Override public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state) { + Log.i(TAG, "setBluetoothHearingAidDeviceConnectionState"); + + setBluetoothHearingAidDeviceConnectionState( + device, state, false /* suppressNoisyIntent */, AudioSystem.DEVICE_NONE); + } + + public int setBluetoothHearingAidDeviceConnectionState( + BluetoothDevice device, int state, boolean suppressNoisyIntent, + int musicDevice) + { + int delay; + synchronized (mConnectedDevices) { + if (!suppressNoisyIntent) { + int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0; + delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_HEARING_AID, + intState, musicDevice); + } else { + delay = 0; + } + queueMsgUnderWakeLock(mAudioHandler, + MSG_SET_HEARING_AID_CONNECTION_STATE, + state, + 0 /* arg2 unused */, + device, + delay); + } + return delay; } public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile) @@ -5246,6 +5375,11 @@ public class AudioService extends IAudioService.Stub mAudioEventWakeLock.release(); break; + case MSG_SET_HEARING_AID_CONNECTION_STATE: + onSetHearingAidConnectionState((BluetoothDevice)msg.obj, msg.arg1); + mAudioEventWakeLock.release(); + break; + case MSG_A2DP_DEVICE_CONFIG_CHANGE: onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj); mAudioEventWakeLock.release(); @@ -5438,14 +5572,8 @@ public class AudioService extends IAudioService.Stub AudioSystem.DEVICE_STATE_UNAVAILABLE, address, ""); mConnectedDevices.remove( makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address)); - synchronized (mCurAudioRoutes) { - // Remove A2DP routes as well - if (mCurAudioRoutes.bluetoothName != null) { - mCurAudioRoutes.bluetoothName = null; - sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, - SENDMSG_NOOP, 0, 0, null, 0); - } - } + // Remove A2DP routes as well + setCurrentAudioRouteName(null); } // must be called synchronized on mConnectedDevices @@ -5480,6 +5608,44 @@ public class AudioService extends IAudioService.Stub makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address)); } + private void setHearingAidVolume(int index) { + synchronized (mHearingAidLock) { + if (mHearingAid != null) { + //hearing aid expect volume value in range -128dB to 0dB + int gainDB = (int)AudioSystem.getStreamVolumeDB(AudioSystem.STREAM_MUSIC, index/10, + AudioSystem.DEVICE_OUT_HEARING_AID); + if (gainDB < BT_HEARING_AID_GAIN_MIN) + gainDB = BT_HEARING_AID_GAIN_MIN; + mHearingAid.setVolume(gainDB); + } + } + } + + // must be called synchronized on mConnectedDevices + private void makeHearingAidDeviceAvailable(String address, String name, String eventSource) { + int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(AudioSystem.DEVICE_OUT_HEARING_AID); + setHearingAidVolume(index); + + AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID, + AudioSystem.DEVICE_STATE_AVAILABLE, address, name); + mConnectedDevices.put( + makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address), + new DeviceListSpec(AudioSystem.DEVICE_OUT_HEARING_AID, name, + address)); + sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE, + AudioSystem.DEVICE_OUT_HEARING_AID, 0, null, 0); + } + + // must be called synchronized on mConnectedDevices + private void makeHearingAidDeviceUnavailable(String address) { + AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID, + AudioSystem.DEVICE_STATE_UNAVAILABLE, address, ""); + mConnectedDevices.remove( + makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address)); + // Remove Hearing Aid routes as well + setCurrentAudioRouteName(null); + } + // must be called synchronized on mConnectedDevices private void cancelA2dpDeviceTimeout() { mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT); @@ -5521,13 +5687,7 @@ public class AudioService extends IAudioService.Stub } else { makeA2dpDeviceUnavailableNow(address); } - synchronized (mCurAudioRoutes) { - if (mCurAudioRoutes.bluetoothName != null) { - mCurAudioRoutes.bluetoothName = null; - sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, - SENDMSG_NOOP, 0, 0, null, 0); - } - } + setCurrentAudioRouteName(null); } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { if (btDevice.isBluetoothDock()) { // this could be a reconnection after a transient disconnection @@ -5543,14 +5703,7 @@ public class AudioService extends IAudioService.Stub } makeA2dpDeviceAvailable(address, btDevice.getName(), "onSetA2dpSinkConnectionState"); - synchronized (mCurAudioRoutes) { - String name = btDevice.getAliasName(); - if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) { - mCurAudioRoutes.bluetoothName = name; - sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, - SENDMSG_NOOP, 0, 0, null, 0); - } - } + setCurrentAudioRouteName(btDevice.getAliasName()); } } } @@ -5581,6 +5734,46 @@ public class AudioService extends IAudioService.Stub } } + private void onSetHearingAidConnectionState(BluetoothDevice btDevice, int state) + { + if (DEBUG_DEVICES) { + Log.d(TAG, "onSetHearingAidConnectionState btDevice=" + btDevice+", state=" + state); + } + if (btDevice == null) { + return; + } + String address = btDevice.getAddress(); + if (!BluetoothAdapter.checkBluetoothAddress(address)) { + address = ""; + } + + synchronized (mConnectedDevices) { + final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, + btDevice.getAddress()); + final DeviceListSpec deviceSpec = mConnectedDevices.get(key); + boolean isConnected = deviceSpec != null; + + if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { + makeHearingAidDeviceUnavailable(address); + setCurrentAudioRouteName(null); + } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { + makeHearingAidDeviceAvailable(address, btDevice.getName(), + "onSetHearingAidConnectionState"); + setCurrentAudioRouteName(btDevice.getAliasName()); + } + } + } + + private void setCurrentAudioRouteName(String name){ + synchronized (mCurAudioRoutes) { + if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) { + mCurAudioRoutes.bluetoothName = name; + sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, + SENDMSG_NOOP, 0, 0, null, 0); + } + } + } + private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice) { if (DEBUG_DEVICES) { @@ -5716,6 +5909,7 @@ public class AudioService extends IAudioService.Stub if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) || mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) || + mAudioHandler.hasMessages(MSG_SET_HEARING_AID_CONNECTION_STATE) || mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) { synchronized (mLastDeviceConnectMsgTime) { long time = SystemClock.uptimeMillis(); diff --git a/services/core/java/com/android/server/backup/BackupUtils.java b/services/core/java/com/android/server/backup/BackupUtils.java index e5d564dec459855a5aa80ccf1e34dc6b4e4f2f0a..d817534551f7b331aae44ec81999cfe6a9107e29 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 storedSigHashes, PackageInfo target) { - if (target == null) { + public static boolean signaturesMatch(ArrayList 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 deviceHashes = new ArrayList(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 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 f1a806bb4074f76c9206015b68df2fd5d09c61ba..4f31e533f8f974e2b264f40a018314ff2bd890a2 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 }; @@ -209,6 +213,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. diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index cb53521c5e7f65a7e676a090baba876e65ef2b74..5e1afeb571de607a72528a4a9e96921c63add6fe 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -282,6 +282,10 @@ class AutomaticBrightnessController { return mBrightnessMapper.isDefaultConfig(); } + public BrightnessConfiguration getDefaultConfig() { + return mBrightnessMapper.getDefaultConfig(); + } + private boolean setDisplayPolicy(int policy) { if (mDisplayPolicy == policy) { return false; diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index c0d259992a4616282d108a8b5c949216aba37bdc..4313d1724214312f7380a348c64fb91cf82364d8 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -206,6 +206,8 @@ public abstract class BrightnessMappingStrategy { /** @return true if the current brightness config is the default one */ public abstract boolean isDefaultConfig(); + public abstract BrightnessConfiguration getDefaultConfig(); + public abstract void dump(PrintWriter pw); private static float normalizeAbsoluteBrightness(int brightness) { @@ -405,6 +407,9 @@ public abstract class BrightnessMappingStrategy { return true; } + @Override + public BrightnessConfiguration getDefaultConfig() { return null; } + @Override public void dump(PrintWriter pw) { pw.println("SimpleMappingStrategy"); @@ -532,6 +537,9 @@ public abstract class BrightnessMappingStrategy { return mDefaultConfig.equals(mConfig); } + @Override + public BrightnessConfiguration getDefaultConfig() { return mDefaultConfig; } + @Override public void dump(PrintWriter pw) { pw.println("PhysicalMappingStrategy"); diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index 3a8e291f7976d47b56da49082d1c4e46cb71590f..2405925285656445c2e515c155161094d891d47d 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 a5c1fe299e4e16d94ced7ece882a4d92a54789f6..c4b2b5ed3ccf83af55af5fe81e246d0b7a5cc9cd 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) { @@ -1876,6 +1877,48 @@ public final class DisplayManagerService extends SystemService { } } + @Override // Binder call + public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS, + "Permission required to read the display's brightness configuration"); + if (userId != UserHandle.getCallingUserId()) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.INTERACT_ACROSS_USERS, + "Permission required to read the display brightness" + + " configuration of another user"); + } + final long token = Binder.clearCallingIdentity(); + try { + final int userSerial = getUserManager().getUserSerialNumber(userId); + synchronized (mSyncRoot) { + BrightnessConfiguration config = + mPersistentDataStore.getBrightnessConfiguration(userSerial); + if (config == null) { + config = mDisplayPowerController.getDefaultBrightnessConfiguration(); + } + return config; + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public BrightnessConfiguration getDefaultBrightnessConfiguration() { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS, + "Permission required to read the display's default brightness configuration"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mSyncRoot) { + return mDisplayPowerController.getDefaultBrightnessConfiguration(); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + @Override // Binder call public void setTemporaryBrightness(int brightness) { mContext.enforceCallingOrSelfPermission( @@ -2031,8 +2074,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/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index fa39ce4f850338574b8cc5c41163d777aca5c525..ff8b88bfa79ce81101133434aa7f69f70d32a307 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -567,6 +567,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } + public BrightnessConfiguration getDefaultBrightnessConfiguration() { + return mAutomaticBrightnessController.getDefaultConfig(); + } + private void sendUpdatePowerState() { synchronized (mLock) { sendUpdatePowerStateLocked(); diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index b7385d85d296123eb700e446bca3c07e4ef104af..5ca9abc8355d0aab033f9e46853e2ca74ebcb79a 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -404,7 +404,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) { mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND; } - mInfo.displayCutout = DisplayCutout.fromResources(res, mInfo.width); + mInfo.displayCutout = DisplayCutout.fromResources(res, mInfo.width, + mInfo.height); mInfo.type = Display.TYPE_BUILT_IN; mInfo.densityDpi = (int)(phys.density * 160 + 0.5f); mInfo.xDpi = phys.xDpi; @@ -583,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(); } } @@ -596,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) { @@ -622,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 e582fdf634720cb5e6b20df76586bac7a4c23b1b..23ee56b24b19d3b0c386bcb42a283f9ec946a3a6 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 83614219a3b55886222f51c7ea73d877efa86129..98e32997e58779ca102c74d77aa78c7aacbf0dfd 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 27327d4eb100c6bf6ae125785102d85dc6911f28..e65637f049752df75d789d763a10a7d6ccdc422a 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 f86d57634bff0aff84ad1b11c80b63a4a49f6828..6111c23f252cc2d6e29c0da3cc1a78e8f7529fbb 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 3293379339566cb5f38838f0e3b1eff0b8828258..e8d6ad455fbf40b17649400b330720830fcaa621 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/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java index d30b13c3b564ba70572df550af2ff1c16271d083..a52dd0bc6caf72c7e149eea0f26ba3ac40a02487 100644 --- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java +++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java @@ -74,6 +74,17 @@ public abstract class AuthenticationClient extends ClientMonitor { } }; + /** + * This method is called when authentication starts. + */ + public abstract void onStart(); + + /** + * This method is called when a fingerprint is authenticated or authentication is stopped + * (cancelled by the user, or an error such as lockout has occurred). + */ + public abstract void onStop(); + public AuthenticationClient(Context context, long halDeviceId, IBinder token, IFingerprintServiceReceiver receiver, int targetUserId, int groupId, long opId, boolean restricted, String owner, Bundle bundle, @@ -220,6 +231,7 @@ public abstract class AuthenticationClient extends ClientMonitor { } result |= true; // we have a valid fingerprint, done resetFailedAttempts(); + onStop(); } return result; } @@ -234,6 +246,7 @@ public abstract class AuthenticationClient extends ClientMonitor { Slog.w(TAG, "start authentication: no fingerprint HAL!"); return ERROR_ESRCH; } + onStart(); try { final int result = daemon.authenticate(mOpId, getGroupId()); if (result != 0) { @@ -266,6 +279,7 @@ public abstract class AuthenticationClient extends ClientMonitor { return 0; } + onStop(); IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "stopAuthentication: no fingerprint HAL!"); diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java index 3eae157c53aa930a97c381e93c44d8971334456e..4100a9a5f71c2f76ae36efcf91d3832a705e1dc3 100644 --- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java +++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java @@ -21,6 +21,7 @@ import android.content.Context; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.IFingerprintServiceReceiver; +import android.media.AudioAttributes; import android.os.IBinder; import android.os.RemoteException; import android.os.VibrationEffect; @@ -39,6 +40,11 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient { protected static final int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. See errno.h. protected static final boolean DEBUG = FingerprintService.DEBUG; private static final long[] DEFAULT_SUCCESS_VIBRATION_PATTERN = new long[] {0, 30}; + private static final AudioAttributes FINGERPRINT_SONFICATION_ATTRIBUTES = + new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) + .build(); private final Context mContext; private final long mHalDeviceId; private final int mTargetUserId; @@ -223,14 +229,14 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient { public final void vibrateSuccess() { Vibrator vibrator = mContext.getSystemService(Vibrator.class); if (vibrator != null) { - vibrator.vibrate(mSuccessVibrationEffect); + vibrator.vibrate(mSuccessVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES); } } public final void vibrateError() { Vibrator vibrator = mContext.getSystemService(Vibrator.class); if (vibrator != null) { - vibrator.vibrate(mErrorVibrationEffect); + vibrator.vibrate(mErrorVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES); } } diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index c3259c312cd796968e0c014b5f4895a4fb986116..fc8aace162dc4b350c3e28e35842d92f2f85f061 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -26,8 +26,10 @@ import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; import android.app.AlarmManager; import android.app.AppOpsManager; +import android.app.IActivityManager; import android.app.PendingIntent; import android.app.SynchronousUserSwitchObserver; +import android.app.TaskStackListener; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -137,6 +139,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death @GuardedBy("this") private IBiometricsFingerprint mDaemon; private IStatusBarService mStatusBarService; + private final IActivityManager mActivityManager; private final PowerManager mPowerManager; private final AlarmManager mAlarmManager; private final UserManager mUserManager; @@ -215,6 +218,30 @@ public class FingerprintService extends SystemService implements IHwBinder.Death } }; + private final TaskStackListener mTaskStackListener = new TaskStackListener() { + @Override + public void onTaskStackChanged() { + try { + if (!(mCurrentClient instanceof AuthenticationClient)) { + return; + } + if (isKeyguard(mCurrentClient.getOwnerString())) { + return; // Keyguard is always allowed + } + List runningTasks = mActivityManager.getTasks(1); + if (!runningTasks.isEmpty()) { + if (runningTasks.get(0).topActivity.getPackageName() + != mCurrentClient.getOwnerString()) { + mCurrentClient.stop(false /* initiatedByClient */); + Slog.e(TAG, "Stopping background authentication"); + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + } + } + }; + public FingerprintService(Context context) { super(context); mContext = context; @@ -230,6 +257,8 @@ public class FingerprintService extends SystemService implements IHwBinder.Death mFailedAttempts = new SparseIntArray(); mStatusBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + mActivityManager = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)) + .getService(); } @Override @@ -824,6 +853,24 @@ public class FingerprintService extends SystemService implements IHwBinder.Death AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token, receiver, mCurrentUserId, groupId, opId, restricted, opPackageName, bundle, dialogReceiver, mStatusBarService) { + @Override + public void onStart() { + try { + mActivityManager.registerTaskStackListener(mTaskStackListener); + } catch (RemoteException e) { + Slog.e(TAG, "Could not register task stack listener", e); + } + } + + @Override + public void onStop() { + try { + mActivityManager.unregisterTaskStackListener(mTaskStackListener); + } catch (RemoteException e) { + Slog.e(TAG, "Could not unregister task stack listener", e); + } + } + @Override public int handleFailedAttempt() { final int currentUser = ActivityManager.getCurrentUser(); diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index a951d470735a1e784a3561e92643f67afc013ad5..451acf4cfc9c7fd2b1041f4bb3bddd3dc8dcd02a 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -17,12 +17,10 @@ package com.android.server.input; import android.annotation.NonNull; -import android.annotation.Nullable; import android.os.LocaleList; import android.os.ShellCallback; import android.util.Log; import android.view.Display; -import com.android.internal.inputmethod.InputMethodSubtypeHandle; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.SomeArgs; @@ -79,8 +77,6 @@ import android.os.Message; import android.os.MessageQueue; import android.os.Process; import android.os.RemoteException; -import android.os.ResultReceiver; -import android.os.ShellCommand; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; @@ -99,8 +95,7 @@ import android.view.KeyEvent; import android.view.PointerIcon; import android.view.Surface; import android.view.ViewConfiguration; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; +import android.widget.Toast; import java.io.File; import java.io.FileDescriptor; @@ -137,7 +132,6 @@ public class InputManagerService extends IInputManager.Stub private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4; private static final int MSG_RELOAD_DEVICE_ALIASES = 5; private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6; - private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7; // Pointer to native input manager service object. private final long mPtr; @@ -174,7 +168,8 @@ public class InputManagerService extends IInputManager.Stub private final ArrayList mTempFullKeyboards = new ArrayList(); // handler thread only private boolean mKeyboardLayoutNotificationShown; - private InputMethodSubtypeHandle mCurrentImeHandle; + private PendingIntent mKeyboardLayoutIntent; + private Toast mSwitchedKeyboardLayoutToast; // State for vibrator tokens. private Object mVibratorLock = new Object(); @@ -1367,82 +1362,6 @@ public class InputManagerService extends IInputManager.Stub } } - @Override // Binder call - @Nullable - public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, - InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) { - InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype); - String key = getLayoutDescriptor(identifier); - final String keyboardLayoutDescriptor; - synchronized (mDataStore) { - keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle); - } - - if (keyboardLayoutDescriptor == null) { - return null; - } - - final KeyboardLayout[] result = new KeyboardLayout[1]; - visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { - @Override - public void visitKeyboardLayout(Resources resources, - int keyboardLayoutResId, KeyboardLayout layout) { - result[0] = layout; - } - }); - if (result[0] == null) { - Slog.w(TAG, "Could not get keyboard layout with descriptor '" - + keyboardLayoutDescriptor + "'."); - } - return result[0]; - } - - @Override - public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, - InputMethodInfo imeInfo, InputMethodSubtype imeSubtype, - String keyboardLayoutDescriptor) { - if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, - "setKeyboardLayoutForInputDevice()")) { - throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); - } - if (keyboardLayoutDescriptor == null) { - throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); - } - if (imeInfo == null) { - throw new IllegalArgumentException("imeInfo must not be null"); - } - InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype); - setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor); - } - - private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier, - InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) { - String key = getLayoutDescriptor(identifier); - synchronized (mDataStore) { - try { - if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) { - if (DEBUG) { - Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor + - " for subtype " + imeHandle + " and device " + identifier + - " using key " + key); - } - if (imeHandle.equals(mCurrentImeHandle)) { - if (DEBUG) { - Slog.d(TAG, "Layout for current subtype changed, switching layout"); - } - SomeArgs args = SomeArgs.obtain(); - args.arg1 = identifier; - args.arg2 = imeHandle; - mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget(); - } - mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); - } - } finally { - mDataStore.saveIfNeeded(); - } - } - } - @Override // Binder call public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor) { @@ -1462,7 +1381,8 @@ public class InputManagerService extends IInputManager.Stub oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); } if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor) - && !Objects.equals(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) { + && !Objects.equals(oldLayout, + mDataStore.getCurrentKeyboardLayout(key))) { mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); } } finally { @@ -1505,51 +1425,43 @@ public class InputManagerService extends IInputManager.Stub } } - // Must be called on handler. - private void handleSwitchInputMethodSubtype(int userId, - @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) { - if (DEBUG) { - Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId - + " ime=" + inputMethodInfo + " subtype=" + subtype); - } - if (inputMethodInfo == null) { - Slog.d(TAG, "No InputMethod is running, ignoring change"); - return; - } - if (subtype != null && !"keyboard".equals(subtype.getMode())) { - Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change"); - return; - } - InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype); - if (!handle.equals(mCurrentImeHandle)) { - mCurrentImeHandle = handle; - handleSwitchKeyboardLayout(null, handle); - } + public void switchKeyboardLayout(int deviceId, int direction) { + mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget(); } // Must be called on handler. - private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier, - InputMethodSubtypeHandle handle) { - synchronized (mInputDevicesLock) { - for (InputDevice device : mInputDevices) { - if (identifier != null && !device.getIdentifier().equals(identifier) || - !device.isFullKeyboard()) { - continue; + private void handleSwitchKeyboardLayout(int deviceId, int direction) { + final InputDevice device = getInputDevice(deviceId); + if (device != null) { + final boolean changed; + final String keyboardLayoutDescriptor; + + String key = getLayoutDescriptor(device.getIdentifier()); + synchronized (mDataStore) { + try { + changed = mDataStore.switchKeyboardLayout(key, direction); + keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout( + key); + } finally { + mDataStore.saveIfNeeded(); } - String key = getLayoutDescriptor(device.getIdentifier()); - boolean changed = false; - synchronized (mDataStore) { - try { - if (mDataStore.switchKeyboardLayout(key, handle)) { - changed = true; - } - } finally { - mDataStore.saveIfNeeded(); - } + } + + if (changed) { + if (mSwitchedKeyboardLayoutToast != null) { + mSwitchedKeyboardLayoutToast.cancel(); + mSwitchedKeyboardLayoutToast = null; } - if (changed) { - reloadKeyboardLayouts(); + if (keyboardLayoutDescriptor != null) { + KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor); + if (keyboardLayout != null) { + mSwitchedKeyboardLayoutToast = Toast.makeText( + mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT); + mSwitchedKeyboardLayoutToast.show(); + } } + + reloadKeyboardLayouts(); } } } @@ -1790,7 +1702,7 @@ public class InputManagerService extends IInputManager.Stub } @Override - public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; pw.println("INPUT MANAGER (dumpsys input)\n"); @@ -1798,49 +1710,8 @@ public class InputManagerService extends IInputManager.Stub if (dumpStr != null) { pw.println(dumpStr); } - pw.println(" Keyboard Layouts:"); - visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { - @Override - public void visitKeyboardLayout(Resources resources, - int keyboardLayoutResId, KeyboardLayout layout) { - pw.println(" \"" + layout + "\": " + layout.getDescriptor()); - } - }); - pw.println(); - synchronized(mDataStore) { - mDataStore.dump(pw, " "); - } - } - - @Override - public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ShellCallback callback, - ResultReceiver resultReceiver) { - (new Shell()).exec(this, in, out, err, args, callback, resultReceiver); - } - - public int onShellCommand(Shell shell, String cmd) { - if (TextUtils.isEmpty(cmd)) { - shell.onHelp(); - return 1; - } - if (cmd.equals("setlayout")) { - if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, - "onShellCommand()")) { - throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); - } - InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle( - shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired())); - String descriptor = shell.getNextArgRequired(); - int vid = Integer.decode(shell.getNextArgRequired()); - int pid = Integer.decode(shell.getNextArgRequired()); - InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid); - setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired()); - } - return 0; } - private boolean checkCallingPermission(String permission, String func) { // Quick check: if the calling permission is me, it's all okay. if (Binder.getCallingPid() == Process.myPid()) { @@ -2169,12 +2040,9 @@ public class InputManagerService extends IInputManager.Stub case MSG_DELIVER_INPUT_DEVICES_CHANGED: deliverInputDevicesChanged((InputDevice[])msg.obj); break; - case MSG_SWITCH_KEYBOARD_LAYOUT: { - SomeArgs args = (SomeArgs)msg.obj; - handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1, - (InputMethodSubtypeHandle)args.arg2); + case MSG_SWITCH_KEYBOARD_LAYOUT: + handleSwitchKeyboardLayout(msg.arg1, msg.arg2); break; - } case MSG_RELOAD_KEYBOARD_LAYOUTS: reloadKeyboardLayouts(); break; @@ -2184,22 +2052,12 @@ public class InputManagerService extends IInputManager.Stub case MSG_RELOAD_DEVICE_ALIASES: reloadDeviceAliases(); break; - case MSG_DELIVER_TABLET_MODE_CHANGED: { + case MSG_DELIVER_TABLET_MODE_CHANGED: SomeArgs args = (SomeArgs) msg.obj; long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32); boolean inTabletMode = (boolean) args.arg1; deliverTabletModeChanged(whenNanos, inTabletMode); break; - } - case MSG_INPUT_METHOD_SUBTYPE_CHANGED: { - final int userId = msg.arg1; - final SomeArgs args = (SomeArgs) msg.obj; - final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1; - final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2; - args.recycle(); - handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype); - break; - } } } } @@ -2341,25 +2199,6 @@ public class InputManagerService extends IInputManager.Stub } } - private class Shell extends ShellCommand { - @Override - public int onCommand(String cmd) { - return onShellCommand(this, cmd); - } - - @Override - public void onHelp() { - final PrintWriter pw = getOutPrintWriter(); - pw.println("Input manager commands:"); - pw.println(" help"); - pw.println(" Print this help text."); - pw.println(""); - pw.println(" setlayout IME_ID IME_SUPTYPE_HASH_CODE" - + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR"); - pw.println(" Sets a keyboard layout for a given IME subtype and input device pair"); - } - } - private final class LocalService extends InputManagerInternal { @Override public void setDisplayViewports(DisplayViewport defaultViewport, @@ -2379,16 +2218,6 @@ public class InputManagerService extends IInputManager.Stub nativeSetInteractive(mPtr, interactive); } - @Override - public void onInputMethodSubtypeChanged(int userId, - @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) { - final SomeArgs someArgs = SomeArgs.obtain(); - someArgs.arg1 = inputMethodInfo; - someArgs.arg2 = subtype; - mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs) - .sendToTarget(); - } - @Override public void toggleCapsLock(int deviceId) { nativeToggleCapsLock(mPtr, deviceId); diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java index c9f8b208469765592e90fd1fc06ada7fcccde6e0..196787aa5cdae4270db735c2f9e55384e2d95208 100644 --- a/services/core/java/com/android/server/input/PersistentDataStore.java +++ b/services/core/java/com/android/server/input/PersistentDataStore.java @@ -16,7 +16,6 @@ package com.android.server.input; -import com.android.internal.inputmethod.InputMethodSubtypeHandle; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; @@ -28,8 +27,6 @@ import org.xmlpull.v1.XmlSerializer; import android.annotation.Nullable; import android.view.Surface; import android.hardware.input.TouchCalibration; -import android.text.TextUtils; -import android.util.ArrayMap; import android.util.AtomicFile; import android.util.Slog; import android.util.Xml; @@ -41,13 +38,10 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -139,26 +133,9 @@ final class PersistentDataStore { } return state.getKeyboardLayouts(); } - public String getKeyboardLayout(String inputDeviceDescriptor, - InputMethodSubtypeHandle imeHandle) { - InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false); - if (state == null) { - return null; - } - return state.getKeyboardLayout(imeHandle); - } - public boolean setKeyboardLayout(String inputDeviceDescriptor, - InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) { - InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true); - if (state.setKeyboardLayout(imeHandle, keyboardLayoutDescriptor)) { - setDirty(); - return true; - } - return false; - } - - public boolean addKeyboardLayout(String inputDeviceDescriptor, String keyboardLayoutDescriptor) { + public boolean addKeyboardLayout(String inputDeviceDescriptor, + String keyboardLayoutDescriptor) { InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true); if (state.addKeyboardLayout(keyboardLayoutDescriptor)) { setDirty(); @@ -177,10 +154,9 @@ final class PersistentDataStore { return false; } - public boolean switchKeyboardLayout(String inputDeviceDescriptor, - InputMethodSubtypeHandle imeHandle) { + public boolean switchKeyboardLayout(String inputDeviceDescriptor, int direction) { InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false); - if (state != null && state.switchKeyboardLayout(imeHandle)) { + if (state != null && state.switchKeyboardLayout(direction)) { setDirty(); return true; } @@ -327,18 +303,6 @@ final class PersistentDataStore { serializer.endDocument(); } - public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + "PersistentDataStore"); - pw.println(prefix + " mLoaded=" + mLoaded); - pw.println(prefix + " mDirty=" + mDirty); - pw.println(prefix + " InputDeviceStates:"); - int i = 0; - for (Map.Entry entry : mInputDevices.entrySet()) { - pw.println(prefix + " " + i++ + ": " + entry.getKey()); - entry.getValue().dump(pw, prefix + " "); - } - } - private static final class InputDeviceState { private static final String[] CALIBRATION_NAME = { "x_scale", "x_ymix", "x_offset", "y_xmix", "y_scale", "y_offset" }; @@ -346,8 +310,7 @@ final class PersistentDataStore { private TouchCalibration[] mTouchCalibration = new TouchCalibration[4]; @Nullable private String mCurrentKeyboardLayout; - private List mUnassociatedKeyboardLayouts = new ArrayList<>(); - private ArrayMap mKeyboardLayouts = new ArrayMap<>(); + private ArrayList mKeyboardLayouts = new ArrayList(); public TouchCalibration getTouchCalibration(int surfaceRotation) { try { @@ -386,34 +349,18 @@ final class PersistentDataStore { } public String[] getKeyboardLayouts() { - if (mUnassociatedKeyboardLayouts.isEmpty()) { + if (mKeyboardLayouts.isEmpty()) { return (String[])ArrayUtils.emptyArray(String.class); } - return mUnassociatedKeyboardLayouts.toArray( - new String[mUnassociatedKeyboardLayouts.size()]); - } - - public String getKeyboardLayout(InputMethodSubtypeHandle handle) { - return mKeyboardLayouts.get(handle); - } - - public boolean setKeyboardLayout(InputMethodSubtypeHandle imeHandle, - String keyboardLayout) { - String existingLayout = mKeyboardLayouts.get(imeHandle); - if (TextUtils.equals(existingLayout, keyboardLayout)) { - return false; - } - mKeyboardLayouts.put(imeHandle, keyboardLayout); - return true; + return mKeyboardLayouts.toArray(new String[mKeyboardLayouts.size()]); } public boolean addKeyboardLayout(String keyboardLayout) { - int index = Collections.binarySearch( - mUnassociatedKeyboardLayouts, keyboardLayout); + int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout); if (index >= 0) { return false; } - mUnassociatedKeyboardLayouts.add(-index - 1, keyboardLayout); + mKeyboardLayouts.add(-index - 1, keyboardLayout); if (mCurrentKeyboardLayout == null) { mCurrentKeyboardLayout = keyboardLayout; } @@ -421,11 +368,11 @@ final class PersistentDataStore { } public boolean removeKeyboardLayout(String keyboardLayout) { - int index = Collections.binarySearch(mUnassociatedKeyboardLayouts, keyboardLayout); + int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout); if (index < 0) { return false; } - mUnassociatedKeyboardLayouts.remove(index); + mKeyboardLayouts.remove(index); updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, index); return true; } @@ -433,34 +380,41 @@ final class PersistentDataStore { private void updateCurrentKeyboardLayoutIfRemoved( String removedKeyboardLayout, int removedIndex) { if (Objects.equals(mCurrentKeyboardLayout, removedKeyboardLayout)) { - if (!mUnassociatedKeyboardLayouts.isEmpty()) { + if (!mKeyboardLayouts.isEmpty()) { int index = removedIndex; - if (index == mUnassociatedKeyboardLayouts.size()) { + if (index == mKeyboardLayouts.size()) { index = 0; } - mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(index); + mCurrentKeyboardLayout = mKeyboardLayouts.get(index); } else { mCurrentKeyboardLayout = null; } } } - public boolean switchKeyboardLayout(InputMethodSubtypeHandle imeHandle) { - final String layout = mKeyboardLayouts.get(imeHandle); - if (!TextUtils.equals(mCurrentKeyboardLayout, layout)) { - mCurrentKeyboardLayout = layout; - return true; + public boolean switchKeyboardLayout(int direction) { + final int size = mKeyboardLayouts.size(); + if (size < 2) { + return false; + } + int index = Collections.binarySearch(mKeyboardLayouts, mCurrentKeyboardLayout); + assert index >= 0; + if (direction > 0) { + index = (index + 1) % size; + } else { + index = (index + size - 1) % size; } - return false; + mCurrentKeyboardLayout = mKeyboardLayouts.get(index); + return true; } public boolean removeUninstalledKeyboardLayouts(Set availableKeyboardLayouts) { boolean changed = false; - for (int i = mUnassociatedKeyboardLayouts.size(); i-- > 0; ) { - String keyboardLayout = mUnassociatedKeyboardLayouts.get(i); + for (int i = mKeyboardLayouts.size(); i-- > 0; ) { + String keyboardLayout = mKeyboardLayouts.get(i); if (!availableKeyboardLayouts.contains(keyboardLayout)) { Slog.i(TAG, "Removing uninstalled keyboard layout " + keyboardLayout); - mUnassociatedKeyboardLayouts.remove(i); + mKeyboardLayouts.remove(i); updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, i); changed = true; } @@ -478,8 +432,13 @@ final class PersistentDataStore { throw new XmlPullParserException( "Missing descriptor attribute on keyboard-layout."); } - String current = parser.getAttributeValue(null, "current"); + if (mKeyboardLayouts.contains(descriptor)) { + throw new XmlPullParserException( + "Found duplicate keyboard layout."); + } + + mKeyboardLayouts.add(descriptor); if (current != null && current.equals("true")) { if (mCurrentKeyboardLayout != null) { throw new XmlPullParserException( @@ -487,32 +446,6 @@ final class PersistentDataStore { } mCurrentKeyboardLayout = descriptor; } - - String inputMethodId = parser.getAttributeValue(null, "input-method-id"); - String inputMethodSubtypeId = - parser.getAttributeValue(null, "input-method-subtype-id"); - if (inputMethodId == null && inputMethodSubtypeId != null - || inputMethodId != null && inputMethodSubtypeId == null) { - throw new XmlPullParserException( - "Found an incomplete input method description"); - } - - if (inputMethodSubtypeId != null) { - InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle( - inputMethodId, Integer.parseInt(inputMethodSubtypeId)); - if (mKeyboardLayouts.containsKey(handle)) { - throw new XmlPullParserException( - "Found duplicate subtype to keyboard layout mapping: " - + handle); - } - mKeyboardLayouts.put(handle, descriptor); - } else { - if (mUnassociatedKeyboardLayouts.contains(descriptor)) { - throw new XmlPullParserException( - "Found duplicate unassociated keyboard layout: " + descriptor); - } - mUnassociatedKeyboardLayouts.add(descriptor); - } } else if (parser.getName().equals("calibration")) { String format = parser.getAttributeValue(null, "format"); String rotation = parser.getAttributeValue(null, "rotation"); @@ -563,31 +496,19 @@ final class PersistentDataStore { } // Maintain invariant that layouts are sorted. - Collections.sort(mUnassociatedKeyboardLayouts); + Collections.sort(mKeyboardLayouts); // Maintain invariant that there is always a current keyboard layout unless // there are none installed. - if (mCurrentKeyboardLayout == null && !mUnassociatedKeyboardLayouts.isEmpty()) { - mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(0); + if (mCurrentKeyboardLayout == null && !mKeyboardLayouts.isEmpty()) { + mCurrentKeyboardLayout = mKeyboardLayouts.get(0); } } public void saveToXml(XmlSerializer serializer) throws IOException { - for (String layout : mUnassociatedKeyboardLayouts) { - serializer.startTag(null, "keyboard-layout"); - serializer.attribute(null, "descriptor", layout); - serializer.endTag(null, "keyboard-layout"); - } - - final int N = mKeyboardLayouts.size(); - for (int i = 0; i < N; i++) { - final InputMethodSubtypeHandle handle = mKeyboardLayouts.keyAt(i); - final String layout = mKeyboardLayouts.valueAt(i); + for (String layout : mKeyboardLayouts) { serializer.startTag(null, "keyboard-layout"); serializer.attribute(null, "descriptor", layout); - serializer.attribute(null, "input-method-id", handle.getInputMethodId()); - serializer.attribute(null, "input-method-subtype-id", - Integer.toString(handle.getSubtypeId())); if (layout.equals(mCurrentKeyboardLayout)) { serializer.attribute(null, "current", "true"); } @@ -612,22 +533,6 @@ final class PersistentDataStore { } } - private void dump(final PrintWriter pw, final String prefix) { - pw.println(prefix + "CurrentKeyboardLayout=" + mCurrentKeyboardLayout); - pw.println(prefix + "UnassociatedKeyboardLayouts=" + mUnassociatedKeyboardLayouts); - pw.println(prefix + "TouchCalibration=" + Arrays.toString(mTouchCalibration)); - pw.println(prefix + "Subtype to Layout Mappings:"); - final int N = mKeyboardLayouts.size(); - if (N != 0) { - for (int i = 0; i < N; i++) { - pw.println(prefix + " " + mKeyboardLayouts.keyAt(i) + ": " - + mKeyboardLayouts.valueAt(i)); - } - } else { - pw.println(prefix + " "); - } - } - private static String surfaceRotationToString(int surfaceRotation) { switch (surfaceRotation) { case Surface.ROTATION_0: return "0"; diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 729ac0c686626838ff7d090e6cc48966793c399a..e02feecbc288809846a29f18196e3135f64d4f83 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -1721,7 +1721,9 @@ public class GnssLocationProvider implements LocationProviderInterface { if (mItarSpeedLimitExceeded) { Log.i(TAG, "Hal reported a speed in excess of ITAR limit." + " GPS/GNSS Navigation output blocked."); - mGnssMetrics.logReceivedLocationStatus(false); + if (mStarted) { + mGnssMetrics.logReceivedLocationStatus(false); + } return; // No output of location allowed } @@ -1738,14 +1740,16 @@ public class GnssLocationProvider implements LocationProviderInterface { Log.e(TAG, "RemoteException calling reportLocation"); } - mGnssMetrics.logReceivedLocationStatus(hasLatLong); - if (hasLatLong) { - if (location.hasAccuracy()) { - mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy()); - } - if (mTimeToFirstFix > 0) { - int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime); - mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes); + if (mStarted) { + mGnssMetrics.logReceivedLocationStatus(hasLatLong); + if (hasLatLong) { + if (location.hasAccuracy()) { + mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy()); + } + if (mTimeToFirstFix > 0) { + int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime); + mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes); + } } } @@ -1754,7 +1758,9 @@ public class GnssLocationProvider implements LocationProviderInterface { if (mTimeToFirstFix == 0 && hasLatLong) { mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime); if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); - mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix); + if (mStarted) { + mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix); + } // notify status listeners mListenerHelper.onFirstFix(mTimeToFirstFix); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 468ec591caa24bd29a92891f5d1ffe1b3c8d2de6..74ebf3e44616de94474edd03d815039d3c008ab9 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -102,6 +102,7 @@ import com.android.internal.util.Preconditions; import com.android.internal.widget.ICheckCredentialProgressCallback; import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockSettingsInternal; import com.android.internal.widget.VerifyCredentialResponse; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -436,6 +437,8 @@ public class LockSettingsService extends ILockSettings.Stub { mStrongAuthTracker.register(mStrongAuth); mSpManager = injector.getSyntheticPasswordManager(mStorage); + + LocalServices.addService(LockSettingsInternal.class, new LocalService()); } /** @@ -1041,14 +1044,10 @@ public class LockSettingsService extends ILockSettings.Stub { private boolean isUserSecure(int userId) { synchronized (mSpManager) { - try { - if (isSyntheticPasswordBasedCredentialLocked(userId)) { - long handle = getSyntheticPasswordHandleLocked(userId); - return mSpManager.getCredentialType(handle, userId) != - LockPatternUtils.CREDENTIAL_TYPE_NONE; - } - } catch (RemoteException e) { - // fall through + if (isSyntheticPasswordBasedCredentialLocked(userId)) { + long handle = getSyntheticPasswordHandleLocked(userId); + return mSpManager.getCredentialType(handle, userId) != + LockPatternUtils.CREDENTIAL_TYPE_NONE; } } return mStorage.hasCredential(userId); @@ -2305,7 +2304,7 @@ public class LockSettingsService extends ILockSettings.Stub { SyntheticPasswordManager.DEFAULT_HANDLE, userId); } - private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException { + private boolean isSyntheticPasswordBasedCredentialLocked(int userId) { if (userId == USER_FRP) { final int type = mStorage.readPersistentDataBlock().type; return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER; @@ -2318,7 +2317,7 @@ public class LockSettingsService extends ILockSettings.Stub { } @VisibleForTesting - protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException { + protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) { long handle = getSyntheticPasswordHandleLocked(userId); // This is a global setting long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, @@ -2326,7 +2325,7 @@ public class LockSettingsService extends ILockSettings.Stub { return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE; } - private void enableSyntheticPasswordLocked() throws RemoteException { + private void enableSyntheticPasswordLocked() { setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM); } @@ -2525,9 +2524,7 @@ public class LockSettingsService extends ILockSettings.Stub { mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId); } - @Override - public long addEscrowToken(byte[] token, int userId) throws RemoteException { - ensureCallerSystemUid(); + private long addEscrowToken(byte[] token, int userId) throws RemoteException { if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId); synchronized (mSpManager) { enableSyntheticPasswordLocked(); @@ -2559,7 +2556,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } - private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException { + private void activateEscrowTokens(AuthenticationToken auth, int userId) { if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId); synchronized (mSpManager) { disableEscrowTokenOnNonManagedDevicesIfNeeded(userId); @@ -2570,17 +2567,13 @@ public class LockSettingsService extends ILockSettings.Stub { } } - @Override - public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException { - ensureCallerSystemUid(); + private boolean isEscrowTokenActive(long handle, int userId) { synchronized (mSpManager) { return mSpManager.existsHandle(handle, userId); } } - @Override - public boolean removeEscrowToken(long handle, int userId) throws RemoteException { - ensureCallerSystemUid(); + private boolean removeEscrowToken(long handle, int userId) { synchronized (mSpManager) { if (handle == getSyntheticPasswordHandleLocked(userId)) { Slog.w(TAG, "Cannot remove password handle"); @@ -2598,10 +2591,8 @@ public class LockSettingsService extends ILockSettings.Stub { } } - @Override - public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, + private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException { - ensureCallerSystemUid(); boolean result; synchronized (mSpManager) { if (!mSpManager.hasEscrowData(userId)) { @@ -2650,10 +2641,8 @@ public class LockSettingsService extends ILockSettings.Stub { return true; } - @Override - public void unlockUserWithToken(long tokenHandle, byte[] token, int userId) + private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) throws RemoteException { - ensureCallerSystemUid(); AuthenticationResult authResult; synchronized (mSpManager) { if (!mSpManager.hasEscrowData(userId)) { @@ -2663,11 +2652,12 @@ public class LockSettingsService extends ILockSettings.Stub { tokenHandle, token, userId); if (authResult.authToken == null) { Slog.w(TAG, "Invalid escrow token supplied"); - return; + return false; } } unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey()); onAuthTokenKnownForUser(userId, authResult.authToken); + return true; } @Override @@ -2732,20 +2722,11 @@ public class LockSettingsService extends ILockSettings.Stub { if (isSyntheticPasswordBasedCredentialLocked(userId)) { mSpManager.destroyEscrowData(userId); } - } catch (RemoteException e) { - Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e); } finally { Binder.restoreCallingIdentity(ident); } } - private void ensureCallerSystemUid() throws SecurityException { - final int callingUid = mInjector.binderGetCallingUid(); - if (callingUid != Process.SYSTEM_UID) { - throw new SecurityException("Only system can call this API."); - } - } - private class DeviceProvisionedObserver extends ContentObserver { private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor( Settings.Global.DEVICE_PROVISIONED); @@ -2834,4 +2815,46 @@ public class LockSettingsService extends ILockSettings.Stub { Settings.Global.DEVICE_PROVISIONED, 0) != 0; } } + + private final class LocalService extends LockSettingsInternal { + + @Override + public long addEscrowToken(byte[] token, int userId) { + try { + return LockSettingsService.this.addEscrowToken(token, userId); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + @Override + public boolean removeEscrowToken(long handle, int userId) { + return LockSettingsService.this.removeEscrowToken(handle, userId); + } + + @Override + public boolean isEscrowTokenActive(long handle, int userId) { + return LockSettingsService.this.isEscrowTokenActive(handle, userId); + } + + @Override + public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, + byte[] token, int requestedQuality, int userId) { + try { + return LockSettingsService.this.setLockCredentialWithToken(credential, type, + tokenHandle, token, requestedQuality, userId); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + @Override + public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) { + try { + return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + } } 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 8efce8602e789000bbeeabfc0f34c9e124113285..f46657c15b5a0637bd2b8788f5b96443baf57e00 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 recoveryAgents = mRecoverableKeyStoreDb.getRecoveryAgents(mUserId); for (int uid : recoveryAgents) { @@ -158,9 +164,15 @@ 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)) { + if (!shouldCreateSnapshot(recoveryAgentUid)) { recreateCurrentVersion = (mRecoverableKeyStoreDb.getSnapshotVersion(mUserId, recoveryAgentUid) != null) && (mRecoverySnapshotStorage.get(recoveryAgentUid) == null); @@ -172,11 +184,6 @@ public class KeySyncTask implements Runnable { } } - if (!mSnapshotListenersStorage.hasListener(recoveryAgentUid)) { - Log.w(TAG, "No pending intent registered for recovery agent " + recoveryAgentUid); - return; - } - PublicKey publicKey; CertPath certPath = mRecoverableKeyStoreDb.getRecoveryServiceCertPath(mUserId, recoveryAgentUid); @@ -284,18 +291,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); } @@ -336,7 +348,7 @@ public class KeySyncTask implements Runnable { * Returns {@code true} if a sync is pending. * @param recoveryAgentUid uid of the recovery agent. */ - private boolean shoudCreateSnapshot(int recoveryAgentUid) { + private boolean shouldCreateSnapshot(int recoveryAgentUid) { int[] types = mRecoverableKeyStoreDb.getRecoverySecretTypes(mUserId, recoveryAgentUid); if (!ArrayUtils.contains(types, KeyChainProtectionParams.TYPE_LOCKSCREEN)) { // Only lockscreen type is supported. diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorage.java index c925329ed81c243572fd3126a811616f68188e9a..bd9f0fdbe63ddcceb6e8c53e2da531636ec2c6ef 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorage.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorage.java @@ -18,6 +18,7 @@ package com.android.server.locksettings.recoverablekeystore; import android.annotation.Nullable; import android.app.PendingIntent; +import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; @@ -36,6 +37,9 @@ public class RecoverySnapshotListenersStorage { @GuardedBy("this") private SparseArray mAgentIntents = new SparseArray<>(); + @GuardedBy("this") + private ArraySet mAgentsWithPendingSnapshots = new ArraySet<>(); + /** * Sets new listener for the recovery agent, identified by {@code uid}. * @@ -46,6 +50,11 @@ public class RecoverySnapshotListenersStorage { int recoveryAgentUid, @Nullable PendingIntent intent) { Log.i(TAG, "Registered listener for agent with uid " + recoveryAgentUid); mAgentIntents.put(recoveryAgentUid, intent); + + if (mAgentsWithPendingSnapshots.contains(recoveryAgentUid)) { + Log.i(TAG, "Snapshot already created for agent. Immediately triggering intent."); + tryToSendIntent(recoveryAgentUid, intent); + } } /** @@ -56,21 +65,39 @@ public class RecoverySnapshotListenersStorage { } /** - * Notifies recovery agent that new snapshot is available. Does nothing if a listener was not - * registered. + * Notifies recovery agent that new snapshot is available. If a recovery agent has not yet + * registered a {@link PendingIntent}, remembers that a snapshot is pending for it, so that + * when it does register, that intent is immediately triggered. * * @param recoveryAgentUid uid of recovery agent. */ public synchronized void recoverySnapshotAvailable(int recoveryAgentUid) { PendingIntent intent = mAgentIntents.get(recoveryAgentUid); - if (intent != null) { - try { - intent.send(); - } catch (PendingIntent.CanceledException e) { - Log.e(TAG, - "Failed to trigger PendingIntent for " + recoveryAgentUid, - e); - } + if (intent == null) { + Log.i(TAG, "Snapshot available for agent " + recoveryAgentUid + + " but agent has not yet initialized. Will notify agent when it does."); + mAgentsWithPendingSnapshots.add(recoveryAgentUid); + return; + } + + tryToSendIntent(recoveryAgentUid, intent); + } + + /** + * Attempts to send {@code intent} for the recovery agent. If this fails, remembers to notify + * the recovery agent immediately if it registers a new intent. + */ + private synchronized void tryToSendIntent(int recoveryAgentUid, PendingIntent intent) { + try { + intent.send(); + mAgentsWithPendingSnapshots.remove(recoveryAgentUid); + Log.d(TAG, "Successfully notified listener."); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, + "Failed to trigger PendingIntent for " + recoveryAgentUid, + e); + // As it failed to trigger, trigger immediately if a new intent is registered later. + mAgentsWithPendingSnapshots.add(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 89ddb6c9eb30641a12cb857769c507cdcc289eb1..2676ee8897af4fe322affbc4adb592842970e621 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 @@ -319,6 +319,20 @@ public class RecoverableKeyStoreDb { new String[] {String.valueOf(userId), String.valueOf(newGenerationId)}); } + /** + * 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}. */ diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java index 8983ec369f55492d8c7a2fe8c3c4123dcec56f97..bda2ed39f09e572c758e5d6ce1aaeec02f26f276 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java @@ -175,7 +175,7 @@ class RecoverableKeyStoreDbContract { /** * The algorithm used to derive cryptographic material from the key and salt. One of * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_SHA256} or - * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_ARGON2ID}. + * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_SCRYPT}. */ static final String COLUMN_NAME_KEY_DERIVATION_ALGORITHM = "key_derivation_algorithm"; diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS index 755c1d6f8aff55ab1e68746f9d69ab99b844674a..8adea0e85d126f1b260723b66b94be1fc87815ba 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/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index ab555532a102a16c82a32113b5850434ee47606f..efca15984e57e55e436ca20b47791674c612f55b 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -2852,6 +2852,32 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli()) .build()); + } else if ("month_over".equals(fake)) { + plans.add(SubscriptionPlan.Builder + .createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z")) + .setTitle("G-Mobile is the carriers name who this plan belongs to") + .setDataLimit(5 * TrafficStats.GB_IN_BYTES, + SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED) + .setDataUsage(6 * TrafficStats.GB_IN_BYTES, + ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli()) + .build()); + plans.add(SubscriptionPlan.Builder + .createRecurringMonthly(ZonedDateTime.parse("2017-03-14T00:00:00.000Z")) + .setTitle("G-Mobile, Throttled after limit") + .setDataLimit(5 * TrafficStats.GB_IN_BYTES, + SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED) + .setDataUsage(5 * TrafficStats.GB_IN_BYTES, + ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli()) + .build()); + plans.add(SubscriptionPlan.Builder + .createRecurringMonthly(ZonedDateTime.parse("2017-03-14T00:00:00.000Z")) + .setTitle("G-Mobile, No data connection after limit") + .setDataLimit(5 * TrafficStats.GB_IN_BYTES, + SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) + .setDataUsage(5 * TrafficStats.GB_IN_BYTES, + ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli()) + .build()); + } else if ("month_none".equals(fake)) { plans.add(SubscriptionPlan.Builder .createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z")) diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java index e5fc6e544f6b26fa8c2f9f309948f2d6e119d286..6907c58f13b02004455602ac8f02c600040ad7be 100644 --- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java +++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java @@ -39,6 +39,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.net.INetworkWatchlistManager; import com.android.server.ServiceThread; import com.android.server.SystemService; +import com.android.server.net.BaseNetdEventCallback; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -139,7 +140,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub { ServiceManager.getService(IpConnectivityLog.SERVICE_NAME)); } - private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() { + private final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() { @Override public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount, long timestamp, int uid) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index b68b98da9a2fb045da902b40a6057df752f64cc6..27eeb93fa3f5f7559a149c9e6ea13daeb30af746 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -256,6 +256,9 @@ public class NotificationManagerService extends SystemService { static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT; static final int SHORT_DELAY = 2000; // 2 seconds + // 1 second past the ANR timeout. + static final int FINISH_TOKEN_TIMEOUT = 11 * 1000; + static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; static final long SNOOZE_UNTIL_UNSPECIFIED = -1; @@ -590,7 +593,7 @@ public class NotificationManagerService extends SystemService { out.startDocument(null, true); out.startTag(null, TAG_NOTIFICATION_POLICY); out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION)); - mZenModeHelper.writeXml(out, forBackup); + mZenModeHelper.writeXml(out, forBackup, null); mRankingHelper.writeXml(out, forBackup); mListeners.writeXml(out, forBackup); mAssistants.writeXml(out, forBackup); @@ -956,6 +959,8 @@ public class NotificationManagerService extends SystemService { boolean queryRemove = false; boolean packageChanged = false; boolean cancelNotifications = true; + boolean hideNotifications = false; + boolean unhideNotifications = false; int reason = REASON_PACKAGE_CHANGED; if (action.equals(Intent.ACTION_PACKAGE_ADDED) @@ -964,7 +969,8 @@ public class NotificationManagerService extends SystemService { || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE) - || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { + || action.equals(Intent.ACTION_PACKAGES_SUSPENDED) + || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) { int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL); String pkgList[] = null; @@ -977,7 +983,12 @@ public class NotificationManagerService extends SystemService { uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); - reason = REASON_PACKAGE_SUSPENDED; + cancelNotifications = false; + hideNotifications = true; + } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) { + pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + cancelNotifications = false; + unhideNotifications = true; } else if (queryRestart) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)}; @@ -1019,9 +1030,15 @@ public class NotificationManagerService extends SystemService { if (cancelNotifications) { cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0, !queryRestart, changeUserId, reason, null); + } else if (hideNotifications) { + hideNotificationsForPackages(pkgList); + } else if (unhideNotifications) { + unhideNotificationsForPackages(pkgList); } + } } + mListeners.onPackagesChanged(removingPackage, pkgList, uidList); mAssistants.onPackagesChanged(removingPackage, pkgList, uidList); mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList); @@ -1291,7 +1308,8 @@ public class NotificationManagerService extends SystemService { NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper, NotificationUsageStats usageStats, AtomicFile policyFile, - ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am) { + ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am, + UsageStatsManagerInternal appUsageStats) { Resources resources = getContext().getResources(); mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(), Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, @@ -1304,7 +1322,7 @@ public class NotificationManagerService extends SystemService { mPackageManagerClient = packageManagerClient; mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); - mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); + mAppUsageStats = appUsageStats; mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); mCompanionManager = companionManager; mActivityManager = activityManager; @@ -1446,7 +1464,8 @@ public class NotificationManagerService extends SystemService { null, snoozeHelper, new NotificationUsageStats(getContext()), new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"), (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE), - getGroupHelper(), ActivityManager.getService()); + getGroupHelper(), ActivityManager.getService(), + LocalServices.getService(UsageStatsManagerInternal.class)); // register for various Intents IntentFilter filter = new IntentFilter(); @@ -1474,6 +1493,7 @@ public class NotificationManagerService extends SystemService { IntentFilter suspendedPkgFilter = new IntentFilter(); suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); + suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, suspendedPkgFilter, null, null); @@ -1782,11 +1802,10 @@ public class NotificationManagerService extends SystemService { * Report to usage stats that the notification was seen. * @param r notification record */ + @GuardedBy("mNotificationLock") protected void reportSeen(NotificationRecord r) { - final int userId = r.sbn.getUserId(); mAppUsageStats.reportEvent(r.sbn.getPackageName(), - userId == UserHandle.USER_ALL ? USER_SYSTEM - : userId, + getRealUserId(r.sbn.getUserId()), UsageEvents.Event.NOTIFICATION_SEEN); } @@ -1858,17 +1877,30 @@ public class NotificationManagerService extends SystemService { return newSuppressedVisualEffects; } + // TODO: log visual differences, not just audible ones + @GuardedBy("mNotificationLock") + protected void maybeRecordInterruptionLocked(NotificationRecord r) { + if (r.isInterruptive()) { + mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(), + r.getChannel().getId(), + getRealUserId(r.sbn.getUserId())); + } + } + /** * Report to usage stats that the notification was clicked. * @param r notification record */ protected void reportUserInteraction(NotificationRecord r) { - final int userId = r.sbn.getUserId(); mAppUsageStats.reportEvent(r.sbn.getPackageName(), - userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId, + getRealUserId(r.sbn.getUserId()), UsageEvents.Event.USER_INTERACTION); } + private int getRealUserId(int userId) { + return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId; + } + @VisibleForTesting NotificationManagerInternal getInternalService() { return mInternalService; @@ -2469,6 +2501,7 @@ public class NotificationManagerService extends SystemService { try { synchronized (mNotificationLock) { final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + if (keys != null) { final int N = keys.length; for (int i = 0; i < N; i++) { @@ -4254,6 +4287,14 @@ public class NotificationManagerService extends SystemService { } } + @GuardedBy("mNotificationLock") + private boolean isPackageSuspendedLocked(NotificationRecord r) { + final String pkg = r.sbn.getPackageName(); + final int callingUid = r.sbn.getUid(); + + return isPackageSuspendedForUser(pkg, callingUid); + } + protected class PostNotificationRunnable implements Runnable { private final String key; @@ -4278,6 +4319,8 @@ public class NotificationManagerService extends SystemService { Slog.i(TAG, "Cannot find enqueued record for key: " + key); return; } + + r.setHidden(isPackageSuspendedLocked(r)); NotificationRecord old = mNotificationsByKey.get(key); final StatusBarNotification n = r.sbn; final Notification notification = n.getNotification(); @@ -4285,6 +4328,7 @@ public class NotificationManagerService extends SystemService { if (index < 0) { mNotificationList.add(r); mUsageStats.registerPostedByApp(r); + r.setInterruptive(true); } else { old = mNotificationList.get(index); mNotificationList.set(index, r); @@ -4295,6 +4339,7 @@ public class NotificationManagerService extends SystemService { // revoke uri permissions for changed uris revokeUriPermissions(r, old); r.isUpdate = true; + r.setInterruptive(isVisuallyInterruptive(old, r)); } mNotificationsByKey.put(n.getKey(), r); @@ -4328,7 +4373,7 @@ public class NotificationManagerService extends SystemService { } else { Slog.e(TAG, "Not posting notification without small icon: " + notification); if (old != null && !old.isCanceled) { - mListeners.notifyRemovedLocked(n, + mListeners.notifyRemovedLocked(r, NotificationListenerService.REASON_ERROR, null); mHandler.post(new Runnable() { @Override @@ -4344,7 +4389,10 @@ public class NotificationManagerService extends SystemService { + n.getPackageName()); } - buzzBeepBlinkLocked(r); + if (!r.isHidden()) { + buzzBeepBlinkLocked(r); + } + maybeRecordInterruptionLocked(r); } finally { int N = mEnqueuedNotifications.size(); for (int i = 0; i < N; i++) { @@ -4359,6 +4407,52 @@ public class NotificationManagerService extends SystemService { } } + /** + * If the notification differs enough visually, consider it a new interruptive notification. + */ + @GuardedBy("mNotificationLock") + @VisibleForTesting + protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) { + Notification oldN = old.sbn.getNotification(); + Notification newN = r.sbn.getNotification(); + if (oldN.extras == null || newN.extras == null) { + return false; + } + if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TITLE), + newN.extras.get(Notification.EXTRA_TITLE))) { + return true; + } + if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TEXT), + newN.extras.get(Notification.EXTRA_TEXT))) { + return true; + } + if (oldN.extras.containsKey(Notification.EXTRA_PROGRESS) && newN.hasCompletedProgress()) { + return true; + } + // Actions + if (Notification.areActionsVisiblyDifferent(oldN, newN)) { + return true; + } + + try { + Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN); + Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN); + + // Style based comparisons + if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) { + return true; + } + + // Remote views + if (Notification.areRemoteViewsChanged(oldB, newB)) { + return true; + } + } catch (Exception e) { + Slog.w(TAG, "error recovering builder", e); + } + return false; + } + /** * Keeps the last 5 packages that have notified, by user. */ @@ -4554,6 +4648,7 @@ public class NotificationManagerService extends SystemService { updateLightsLocked(); } if (buzz || beep || blink) { + record.setInterruptive(true); MetricsLogger.action(record.getLogMaker() .setCategory(MetricsEvent.NOTIFICATION_ALERT) .setType(MetricsEvent.TYPE_OPEN) @@ -4790,7 +4885,7 @@ public class NotificationManagerService extends SystemService { { mHandler.removeCallbacksAndMessages(token); Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, token); - mHandler.sendMessageDelayed(m, 5); + mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT); } private void handleKillTokenTimeout(IBinder token) @@ -4955,7 +5050,7 @@ public class NotificationManagerService extends SystemService { private void handleSendRankingUpdate() { synchronized (mNotificationLock) { - mListeners.notifyRankingUpdateLocked(); + mListeners.notifyRankingUpdateLocked(null); } } @@ -5140,7 +5235,7 @@ public class NotificationManagerService extends SystemService { if (reason != REASON_SNOOZED) { r.isCanceled = true; } - mListeners.notifyRemovedLocked(r.sbn, reason, r.getStats()); + mListeners.notifyRemovedLocked(r, reason, r.getStats()); mHandler.post(new Runnable() { @Override public void run() { @@ -5249,6 +5344,7 @@ public class NotificationManagerService extends SystemService { final String pkg, final String tag, final int id, final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, final int userId, final int reason, final ManagedServiceInfo listener) { + // In enqueueNotificationInternal notifications are added by scheduling the // work on the worker handler. Hence, we also schedule the cancel on this // handler to avoid a scenario where an add notification call followed by a @@ -5640,6 +5736,42 @@ public class NotificationManagerService extends SystemService { return -1; } + @VisibleForTesting + protected void hideNotificationsForPackages(String[] pkgs) { + synchronized (mNotificationLock) { + List pkgList = Arrays.asList(pkgs); + List changedNotifications = new ArrayList<>(); + int numNotifications = mNotificationList.size(); + for (int i = 0; i < numNotifications; i++) { + NotificationRecord rec = mNotificationList.get(i); + if (pkgList.contains(rec.sbn.getPackageName())) { + rec.setHidden(true); + changedNotifications.add(rec); + } + } + + mListeners.notifyHiddenLocked(changedNotifications); + } + } + + @VisibleForTesting + protected void unhideNotificationsForPackages(String[] pkgs) { + synchronized (mNotificationLock) { + List pkgList = Arrays.asList(pkgs); + List changedNotifications = new ArrayList<>(); + int numNotifications = mNotificationList.size(); + for (int i = 0; i < numNotifications; i++) { + NotificationRecord rec = mNotificationList.get(i); + if (pkgList.contains(rec.sbn.getPackageName())) { + rec.setHidden(false); + changedNotifications.add(rec); + } + } + + mListeners.notifyUnhiddenLocked(changedNotifications); + } + } + private void updateNotificationPulse() { synchronized (mNotificationLock) { updateLightsLocked(); @@ -5759,6 +5891,7 @@ public class NotificationManagerService extends SystemService { Bundle snoozeCriteria = new Bundle(); Bundle showBadge = new Bundle(); Bundle userSentiment = new Bundle(); + Bundle hidden = new Bundle(); for (int i = 0; i < N; i++) { NotificationRecord record = mNotificationList.get(i); if (!isVisibleToListener(record.sbn, info)) { @@ -5785,6 +5918,7 @@ public class NotificationManagerService extends SystemService { snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria()); showBadge.putBoolean(key, record.canShowBadge()); userSentiment.putInt(key, record.getUserSentiment()); + hidden.putBoolean(key, record.isHidden()); } final int M = keys.size(); String[] keysAr = keys.toArray(new String[M]); @@ -5795,7 +5929,7 @@ public class NotificationManagerService extends SystemService { } return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides, suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys, - channels, overridePeople, snoozeCriteria, showBadge, userSentiment); + channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden); } boolean hasCompanionDevice(ManagedServiceInfo info) { @@ -6084,6 +6218,16 @@ public class NotificationManagerService extends SystemService { */ @GuardedBy("mNotificationLock") public void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn) { + notifyPostedLocked(r, oldSbn, true); + } + + /** + * @param notifyAllListeners notifies all listeners if true, else only notifies listeners + * targetting <= O_MR1 + */ + @GuardedBy("mNotificationLock") + private void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn, + boolean notifyAllListeners) { // Lazily initialized snapshots of the notification. StatusBarNotification sbn = r.sbn; TrimCache trimCache = new TrimCache(sbn); @@ -6097,6 +6241,21 @@ public class NotificationManagerService extends SystemService { if (!oldSbnVisible && !sbnVisible) { continue; } + + // If the notification is hidden, don't notifyPosted listeners targeting < P. + // Instead, those listeners will receive notifyPosted when the notification is + // unhidden. + if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) { + continue; + } + + // If we shouldn't notify all listeners, this means the hidden state of + // a notification was changed. Don't notifyPosted listeners targeting >= P. + // Instead, those listeners will receive notifyRankingUpdate. + if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) { + continue; + } + final NotificationRankingUpdate update = makeRankingUpdateLocked(info); // This notification became invisible -> remove the old one. @@ -6151,8 +6310,9 @@ public class NotificationManagerService extends SystemService { * asynchronously notify all listeners about a removed notification */ @GuardedBy("mNotificationLock") - public void notifyRemovedLocked(StatusBarNotification sbn, int reason, + public void notifyRemovedLocked(NotificationRecord r, int reason, NotificationStats notificationStats) { + final StatusBarNotification sbn = r.sbn; // make a copy in case changes are made to the underlying Notification object // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the // notification @@ -6161,6 +6321,21 @@ public class NotificationManagerService extends SystemService { if (!isVisibleToListener(sbn, info)) { continue; } + + // don't notifyRemoved for listeners targeting < P + // if not for reason package suspended + if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED + && info.targetSdkVersion < Build.VERSION_CODES.P) { + continue; + } + + // don't notifyRemoved for listeners targeting >= P + // if the reason is package suspended + if (reason == REASON_PACKAGE_SUSPENDED + && info.targetSdkVersion >= Build.VERSION_CODES.P) { + continue; + } + // Only assistants can get stats final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service) ? notificationStats : null; @@ -6175,21 +6350,44 @@ public class NotificationManagerService extends SystemService { } /** - * asynchronously notify all listeners about a reordering of notifications + * Asynchronously notify all listeners about a reordering of notifications + * unless changedHiddenNotifications is populated. + * If changedHiddenNotifications is populated, there was a change in the hidden state + * of the notifications. In this case, we only send updates to listeners that + * target >= P. */ @GuardedBy("mNotificationLock") - public void notifyRankingUpdateLocked() { + public void notifyRankingUpdateLocked(List changedHiddenNotifications) { + boolean isHiddenRankingUpdate = changedHiddenNotifications != null + && changedHiddenNotifications.size() > 0; + for (final ManagedServiceInfo serviceInfo : getServices()) { if (!serviceInfo.isEnabledForCurrentProfiles()) { continue; } - final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo); - mHandler.post(new Runnable() { - @Override - public void run() { - notifyRankingUpdate(serviceInfo, update); + + boolean notifyThisListener = false; + if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >= + Build.VERSION_CODES.P) { + for (NotificationRecord rec : changedHiddenNotifications) { + if (isVisibleToListener(rec.sbn, serviceInfo)) { + notifyThisListener = true; + break; + } } - }); + } + + if (notifyThisListener || !isHiddenRankingUpdate) { + final NotificationRankingUpdate update = makeRankingUpdateLocked( + serviceInfo); + + mHandler.post(new Runnable() { + @Override + public void run() { + notifyRankingUpdate(serviceInfo, update); + } + }); + } } } @@ -6208,6 +6406,52 @@ public class NotificationManagerService extends SystemService { } } + /** + * asynchronously notify relevant listeners their notification is hidden + * NotificationListenerServices that target P+: + * NotificationListenerService#notifyRankingUpdateLocked() + * NotificationListenerServices that target <= P: + * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED. + */ + @GuardedBy("mNotificationLock") + public void notifyHiddenLocked(List changedNotifications) { + if (changedNotifications == null || changedNotifications.size() == 0) { + return; + } + + notifyRankingUpdateLocked(changedNotifications); + + // for listeners that target < P, notifyRemoveLocked + int numChangedNotifications = changedNotifications.size(); + for (int i = 0; i < numChangedNotifications; i++) { + NotificationRecord rec = changedNotifications.get(i); + mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats()); + } + } + + /** + * asynchronously notify relevant listeners their notification is unhidden + * NotificationListenerServices that target P+: + * NotificationListenerService#notifyRankingUpdateLocked() + * NotificationListenerServices that target <= P: + * NotificationListeners#notifyPostedLocked() + */ + @GuardedBy("mNotificationLock") + public void notifyUnhiddenLocked(List changedNotifications) { + if (changedNotifications == null || changedNotifications.size() == 0) { + return; + } + + notifyRankingUpdateLocked(changedNotifications); + + // for listeners that target < P, notifyPostedLocked + int numChangedNotifications = changedNotifications.size(); + for (int i = 0; i < numChangedNotifications; i++) { + NotificationRecord rec = changedNotifications.get(i); + mListeners.notifyPostedLocked(rec, rec.sbn, false); + } + } + public void notifyInterruptionFilterChanged(final int interruptionFilter) { for (final ManagedServiceInfo serviceInfo : getServices()) { if (!serviceInfo.isEnabledForCurrentProfiles()) { @@ -6436,6 +6680,22 @@ public class NotificationManagerService extends SystemService { } } + @VisibleForTesting + protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) { + // only use for testing: mimic receive broadcast that package is (un)suspended + // but does not actually (un)suspend the package + final Bundle extras = new Bundle(); + extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, + new String[]{pkg}); + + final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED + : Intent.ACTION_PACKAGES_UNSUSPENDED; + final Intent intent = new Intent(action); + intent.putExtras(extras); + + mPackageIntentReceiver.onReceive(getContext(), intent); + } + /** * Wrapper for a StatusBarNotification object that allows transfer across a oneway * binder without sending large amounts of data over a oneway transaction. @@ -6464,7 +6724,9 @@ public class NotificationManagerService extends SystemService { + "allow_assistant COMPONENT\n" + "remove_assistant COMPONENT\n" + "allow_dnd PACKAGE\n" - + "disallow_dnd PACKAGE"; + + "disallow_dnd PACKAGE\n" + + "suspend_package PACKAGE\n" + + "unsuspend_package PACKAGE"; @Override public int onCommand(String cmd) { @@ -6533,7 +6795,16 @@ public class NotificationManagerService extends SystemService { getBinderService().setNotificationAssistantAccessGranted(cn, false); } break; - + case "suspend_package": { + // only use for testing + simulatePackageSuspendBroadcast(true, getNextArgRequired()); + } + break; + case "unsuspend_package": { + // only use for testing + simulatePackageSuspendBroadcast(false, getNextArgRequired()); + } + break; default: return handleDefaultCommands(cmd); } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 4404c4848c600775d5341d28e3fb7005dd587662..c88708551662db8b2806e89a1307a28091160913 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -103,6 +103,9 @@ public final class NotificationRecord { // is this notification currently being intercepted by Zen Mode? private boolean mIntercept; + // is this notification hidden since the app pkg is suspended? + private boolean mHidden; + // The timestamp used for ranking. private long mRankingTimeMs; @@ -145,6 +148,7 @@ public final class NotificationRecord { private final List mAdjustments; private final NotificationStats mStats; private int mUserSentiment; + private boolean mIsInterruptive; @VisibleForTesting public NotificationRecord(Context context, StatusBarNotification sbn, @@ -352,6 +356,7 @@ public final class NotificationRecord { mPackagePriority = previous.mPackagePriority; mPackageVisibility = previous.mPackageVisibility; mIntercept = previous.mIntercept; + mHidden = previous.mHidden; mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs()); mCreationTimeMs = previous.mCreationTimeMs; mVisibleSinceMs = previous.mVisibleSinceMs; @@ -497,6 +502,7 @@ public final class NotificationRecord { + NotificationListenerService.Ranking.importanceToString(mImportance)); pw.println(prefix + "mImportanceExplanation=" + mImportanceExplanation); pw.println(prefix + "mIntercept=" + mIntercept); + pw.println(prefix + "mHidden==" + mHidden); pw.println(prefix + "mGlobalSortKey=" + mGlobalSortKey); pw.println(prefix + "mRankingTimeMs=" + mRankingTimeMs); pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs); @@ -519,6 +525,7 @@ public final class NotificationRecord { pw.println(prefix + "mLight= " + mLight); pw.println(prefix + "mShowBadge=" + mShowBadge); pw.println(prefix + "mColorized=" + notification.isColorized()); + pw.println(prefix + "mIsInterruptive=" + mIsInterruptive); pw.println(prefix + "effectiveNotificationChannel=" + getChannel()); if (getPeopleOverride() != null) { pw.println(prefix + "overridePeople= " + TextUtils.join(",", getPeopleOverride())); @@ -700,6 +707,15 @@ public final class NotificationRecord { return mIntercept; } + public void setHidden(boolean hidden) { + mHidden = hidden; + } + + public boolean isHidden() { + return mHidden; + } + + public void setSuppressedVisualEffects(int effects) { mSuppressedVisualEffects = effects; } @@ -888,6 +904,14 @@ public final class NotificationRecord { return mPeopleOverride; } + public void setInterruptive(boolean interruptive) { + mIsInterruptive = interruptive; + } + + public boolean isInterruptive() { + return mIsInterruptive; + } + protected void setPeopleOverride(ArrayList people) { mPeopleOverride = people; } diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index b280bde657d8dfce9e48795655a764ba4bf18568..f163113209722b792560f0344cedb830d3d282ac 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -29,18 +29,23 @@ import android.app.NotificationChannelGroup; import android.app.NotificationManager; import android.content.Context; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ParceledListSlice; +import android.content.pm.Signature; +import android.content.res.Resources; import android.metrics.LogMaker; import android.os.Build; import android.os.UserHandle; +import android.print.PrintManager; import android.provider.Settings.Secure; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.RankingHelperProto; import android.service.notification.RankingHelperProto.RecordProto; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.Pair; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; @@ -95,12 +100,18 @@ public class RankingHelper implements RankingConfig { private final ArrayMap mRecords = new ArrayMap<>(); // pkg|uid => Record private final ArrayMap mProxyByGroupTmp = new ArrayMap<>(); private final ArrayMap mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record + private final ArrayMap, Boolean> mSystemAppCache = new ArrayMap<>(); private final Context mContext; private final RankingHandler mRankingHandler; private final PackageManager mPm; private SparseBooleanArray mBadgingEnabled; + private Signature[] mSystemSignature; + private String mPermissionControllerPackageName; + private String mServicesSystemSharedLibPackageName; + private String mSharedSystemSharedLibPackageName; + public RankingHelper(Context context, PackageManager pm, RankingHandler rankingHandler, ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames) { mContext = context; @@ -130,6 +141,8 @@ public class RankingHelper implements RankingConfig { Slog.w(TAG, "Problem accessing extractor " + extractorNames[i] + ".", e); } } + + getSignatures(); } @SuppressWarnings("unchecked") @@ -571,7 +584,7 @@ public class RankingHelper implements RankingConfig { if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) { throw new IllegalArgumentException("Reserved id"); } - + final boolean isSystemApp = isSystemPackage(pkg, uid); NotificationChannel existing = r.channels.get(channel.getId()); // Keep most of the existing settings if (existing != null && fromTargetApp) { @@ -597,6 +610,11 @@ public class RankingHelper implements RankingConfig { existing.setImportance(channel.getImportance()); } + // system apps can bypass dnd if the user hasn't changed any fields on the channel yet + if (existing.getUserLockedFields() == 0 & isSystemApp) { + existing.setBypassDnd(channel.canBypassDnd()); + } + updateConfig(); return; } @@ -604,9 +622,12 @@ public class RankingHelper implements RankingConfig { || channel.getImportance() > NotificationManager.IMPORTANCE_MAX) { throw new IllegalArgumentException("Invalid importance level"); } + // Reset fields that apps aren't allowed to set. - if (fromTargetApp) { + if (fromTargetApp && !isSystemApp) { channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX); + } + if (fromTargetApp) { channel.setLockscreenVisibility(r.visibility); } clearLockedFields(channel); @@ -616,6 +637,7 @@ public class RankingHelper implements RankingConfig { if (!r.showBadge) { channel.setShowBadge(false); } + r.channels.put(channel.getId(), channel); MetricsLogger.action(getChannelLog(channel, pkg).setType( MetricsProto.MetricsEvent.TYPE_OPEN)); @@ -625,6 +647,65 @@ public class RankingHelper implements RankingConfig { channel.unlockFields(channel.getUserLockedFields()); } + /** + * Determine whether a package is a "system package", in which case certain things (like + * bypassing DND) should be allowed. + */ + private boolean isSystemPackage(String pkg, int uid) { + Pair app = new Pair(pkg, uid); + if (mSystemAppCache.containsKey(app)) { + return mSystemAppCache.get(app); + } + + PackageInfo pi; + try { + pi = mPm.getPackageInfoAsUser( + pkg, PackageManager.GET_SIGNATURES, UserHandle.getUserId(uid)); + } catch (NameNotFoundException e) { + Slog.w(TAG, "Can't find pkg", e); + return false; + } + boolean isSystem = (mSystemSignature[0] != null + && mSystemSignature[0].equals(getFirstSignature(pi))) + || pkg.equals(mPermissionControllerPackageName) + || pkg.equals(mServicesSystemSharedLibPackageName) + || pkg.equals(mSharedSystemSharedLibPackageName) + || pkg.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME) + || isDeviceProvisioningPackage(pkg); + mSystemAppCache.put(app, isSystem); + return isSystem; + } + + private Signature getFirstSignature(PackageInfo pkg) { + if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) { + return pkg.signatures[0]; + } + return null; + } + + private Signature getSystemSignature() { + try { + final PackageInfo sys = mPm.getPackageInfoAsUser( + "android", PackageManager.GET_SIGNATURES, UserHandle.USER_SYSTEM); + return getFirstSignature(sys); + } catch (NameNotFoundException e) { + } + return null; + } + + private boolean isDeviceProvisioningPackage(String packageName) { + String deviceProvisioningPackage = mContext.getResources().getString( + com.android.internal.R.string.config_deviceProvisioningPackage); + return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName); + } + + private void getSignatures() { + mSystemSignature = new Signature[]{getSystemSignature()}; + mPermissionControllerPackageName = mPm.getPermissionControllerPackageName(); + mServicesSystemSharedLibPackageName = mPm.getServicesSystemSharedLibraryPackageName(); + mSharedSystemSharedLibPackageName = mPm.getSharedSystemSharedLibraryPackageName(); + } + @Override public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel, boolean fromUser) { diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index aa1f7d95845f5273cef63773549cad73d4e2a3bb..5c823433afafbb01b83fb94ec57a3abb6a89e854 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -56,6 +56,7 @@ import android.service.notification.ZenModeConfig.ScheduleInfo; import android.service.notification.ZenModeConfig.ZenRule; import android.service.notification.ZenModeProto; import android.util.AndroidRuntimeException; +import android.util.ArrayMap; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -234,25 +235,12 @@ public class ZenModeHelper { config = mDefaultConfig.copy(); config.user = user; } - enforceDefaultRulesExist(config); synchronized (mConfig) { setConfigLocked(config, reason); } cleanUpZenRules(); } - private void enforceDefaultRulesExist(ZenModeConfig config) { - for (String id : ZenModeConfig.DEFAULT_RULE_IDS) { - if (!config.automaticRules.containsKey(id)) { - if (id.equals(ZenModeConfig.EVENTS_DEFAULT_RULE_ID)) { - appendDefaultEventRules(config); - } else if (id.equals(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID)) { - appendDefaultEveryNightRule(config); - } - } - } - } - public int getZenModeListenerInterruptionFilter() { return NotificationManager.zenModeToInterruptionFilter(mZenMode); } @@ -623,43 +611,59 @@ public class ZenModeHelper { public void readXml(XmlPullParser parser, boolean forRestore) throws XmlPullParserException, IOException { - final ZenModeConfig config = ZenModeConfig.readXml(parser); + ZenModeConfig config = ZenModeConfig.readXml(parser); + String reason = "readXml"; + if (config != null) { - if (config.version < ZenModeConfig.XML_VERSION || forRestore) { - Settings.Global.putInt(mContext.getContentResolver(), - Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1); - } if (forRestore) { //TODO: http://b/22388012 if (config.user != UserHandle.USER_SYSTEM) { return; } config.manualRule = null; // don't restore the manual rule - long time = System.currentTimeMillis(); - if (config.automaticRules != null) { - for (ZenRule automaticRule : config.automaticRules.values()) { + } + + boolean resetToDefaultRules = true; + long time = System.currentTimeMillis(); + if (config.automaticRules != null && config.automaticRules.size() > 0) { + for (ZenRule automaticRule : config.automaticRules.values()) { + if (forRestore) { // don't restore transient state from restored automatic rules automaticRule.snoozing = false; automaticRule.condition = null; automaticRule.creationTime = time; } + resetToDefaultRules &= !automaticRule.enabled; + } + } + + if (config.version < ZenModeConfig.XML_VERSION || forRestore) { + Settings.Global.putInt(mContext.getContentResolver(), + Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1); + + // resets zen automatic rules to default + // if all prev auto rules were disabled on update + if (resetToDefaultRules) { + config.automaticRules = new ArrayMap<>(); + appendDefaultRules(config); + reason += ", reset to default rules"; } } - if (DEBUG) Log.d(TAG, "readXml"); + if (DEBUG) Log.d(TAG, reason); synchronized (mConfig) { - setConfigLocked(config, "readXml"); + setConfigLocked(config, reason); } } } - public void writeXml(XmlSerializer out, boolean forBackup) throws IOException { + public void writeXml(XmlSerializer out, boolean forBackup, Integer version) throws IOException { final int N = mConfigs.size(); for (int i = 0; i < N; i++) { //TODO: http://b/22388012 if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) { continue; } - mConfigs.valueAt(i).writeXml(out); + mConfigs.valueAt(i).writeXml(out, version); } } @@ -874,7 +878,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,17 +894,30 @@ 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; @@ -1183,15 +1207,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 e6c226210f51ac00df782980542dceb053c560ea..fa0a97b6be809623d0d605f75340fa4dc9e0cdfe 100755 --- 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; @@ -2593,7 +2594,7 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_PRIVILEGED, 0); - // Collected privileged system packages. + // Collect privileged system packages. final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); scanDirTracedLI(privilegedAppDir, mDefParseFlags @@ -2612,7 +2613,7 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_SYSTEM, 0); - // Collected privileged vendor packages. + // Collect privileged vendor packages. File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app"); try { privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile(); @@ -2643,6 +2644,40 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_VENDOR, 0); + // Collect privileged odm packages. /odm is another vendor partition + // other than /vendor. + File privilegedOdmAppDir = new File(Environment.getOdmDirectory(), + "priv-app"); + try { + privilegedOdmAppDir = privilegedOdmAppDir.getCanonicalFile(); + } catch (IOException e) { + // failed to look up canonical path, continue with original one + } + scanDirTracedLI(privilegedOdmAppDir, + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_VENDOR + | SCAN_AS_PRIVILEGED, + 0); + + // Collect ordinary odm packages. /odm is another vendor partition + // other than /vendor. + File odmAppDir = new File(Environment.getOdmDirectory(), "app"); + try { + odmAppDir = odmAppDir.getCanonicalFile(); + } catch (IOException e) { + // failed to look up canonical path, continue with original one + } + scanDirTracedLI(odmAppDir, + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_VENDOR, + 0); + // Collect all OEM packages. final File oemAppDir = new File(Environment.getOemDirectory(), "app"); scanDirTracedLI(oemAppDir, @@ -2867,7 +2902,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; @@ -2876,7 +2912,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; @@ -4074,14 +4111,24 @@ public class PackageManagerService extends IPackageManager.Stub @Nullable ComponentName component, @ComponentType int type) { if (type == TYPE_ACTIVITY) { final PackageParser.Activity activity = mActivities.mActivities.get(component); - return activity != null - ? (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 - : false; + if (activity == null) { + return false; + } + final boolean visibleToInstantApp = + (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; + final boolean explicitlyVisibleToInstantApp = + (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; + return visibleToInstantApp && explicitlyVisibleToInstantApp; } else if (type == TYPE_RECEIVER) { final PackageParser.Activity activity = mReceivers.mActivities.get(component); - return activity != null - ? (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 - : false; + if (activity == null) { + return false; + } + final boolean visibleToInstantApp = + (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; + final boolean explicitlyVisibleToInstantApp = + (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; + return visibleToInstantApp && !explicitlyVisibleToInstantApp; } else if (type == TYPE_SERVICE) { final PackageParser.Service service = mServices.mServices.get(component); return service != null @@ -4126,6 +4173,10 @@ public class PackageManagerService extends IPackageManager.Stub return false; } if (callerIsInstantApp) { + // both caller and target are both instant, but, different applications, filter + if (ps.getInstantApp(userId)) { + return true; + } // request for a specific component; if it hasn't been explicitly exposed through // property or instrumentation target, filter if (component != null) { @@ -4138,7 +4189,7 @@ public class PackageManagerService extends IPackageManager.Stub return !isComponentVisibleToInstantApp(component, componentType); } // request for application; if no components have been explicitly exposed, filter - return ps.getInstantApp(userId) || !ps.pkg.visibleToInstantApps; + return !ps.pkg.visibleToInstantApps; } if (ps.getInstantApp(userId)) { // caller can see all components of all instant applications, don't filter @@ -8672,6 +8723,7 @@ public class PackageManagerService extends IPackageManager.Stub disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */, null /* originalPkgSetting */, null, parseFlags, scanFlags, (pkg == mPlatformPackage), user); + applyPolicy(pkg, parseFlags, scanFlags); scanPackageOnlyLI(request, mFactoryTest, -1L); } } @@ -9961,6 +10013,10 @@ public class PackageManagerService extends IPackageManager.Stub return scanFlags; } + // TODO: scanPackageNewLI() and scanPackageOnly() should be merged. But, first, commiting + // the results / removing app data needs to be moved up a level to the callers of this + // method. Also, we need to solve the problem of potentially creating a new shared user + // setting. That can probably be done later and patch things up after the fact. @GuardedBy("mInstallLock") private PackageParser.Package scanPackageNewLI(@NonNull PackageParser.Package pkg, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @@ -11785,6 +11841,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 { @@ -18214,9 +18272,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); @@ -18235,7 +18295,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); } @@ -23372,6 +23433,36 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); permName, packageName, flagMask, flagValues, userId); } + @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); @@ -23836,6 +23927,15 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); return PackageManagerService.this.canViewInstantApps(callingUid, userId); } + @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) { diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java index 520ed2526b1799b94b42a371f9b5365432d2fc89..eeaa3330dee48d395ee829f7362d6ea7bb4548ac 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 265cc8ebe4d36d2c9aa1081456ef93a7f93d30ca..15b4617294952d9da2a0c9c97e22ee755db4b919 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 4abcce16f777a3317e4472607d94a57b6e00bd5c..83fe1c9eed5c9978a83ef15c978caa1230bc9853 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -55,6 +55,7 @@ import android.provider.Telephony.Sms.Intents; import android.security.Credentials; import android.service.textclassifier.TextClassifierService; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -829,13 +830,11 @@ public final class DefaultPermissionGrantPolicy { } // TextClassifier Service - ComponentName textClassifierComponent = - TextClassifierService.getServiceComponentName(mContext); - if (textClassifierComponent != null) { - Intent textClassifierServiceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE) - .setComponent(textClassifierComponent); + String textClassifierPackageName = + mContext.getPackageManager().getSystemTextClassifierPackageName(); + if (!TextUtils.isEmpty(textClassifierPackageName)) { PackageParser.Package textClassifierPackage = - getDefaultSystemHandlerServicePackage(textClassifierServiceIntent, userId); + getSystemPackage(textClassifierPackageName); if (textClassifierPackage != null && doesPackageSupportRuntimePermissions(textClassifierPackage)) { grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, true, userId); @@ -1240,6 +1239,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/BarController.java b/services/core/java/com/android/server/policy/BarController.java index c906705ae5a9c13a4deeab9db6cea93a52be5ed5..cf88bd5364a7a1f833191c5f0743b081ba46f3ef 100644 --- a/services/core/java/com/android/server/policy/BarController.java +++ b/services/core/java/com/android/server/policy/BarController.java @@ -20,6 +20,7 @@ import static com.android.server.wm.proto.BarControllerProto.STATE; import static com.android.server.wm.proto.BarControllerProto.TRANSIENT_STATE; import android.app.StatusBarManager; +import android.graphics.Rect; import android.os.Handler; import android.os.Message; import android.os.SystemClock; @@ -68,6 +69,7 @@ public class BarController { private boolean mShowTransparent; private boolean mSetUnHideFlagWhenNextTransparent; private boolean mNoAnimationOnNextShow; + private final Rect mContentFrame = new Rect(); private OnBarVisibilityChangedListener mVisibilityChangeListener; @@ -87,6 +89,15 @@ public class BarController { mWin = win; } + /** + * Sets the frame within which the bar will display its content. + * + * This is used to determine if letterboxes interfere with the display of such content. + */ + public void setContentFrame(Rect frame) { + mContentFrame.set(frame); + } + public void setShowTransparent(boolean transparent) { if (transparent != mShowTransparent) { mShowTransparent = transparent; @@ -135,7 +146,8 @@ public class BarController { } else { vis &= ~mTranslucentFlag; } - if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) { + if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 + && isTransparentAllowed(win)) { vis |= mTransparentFlag; } else { vis &= ~mTransparentFlag; @@ -148,6 +160,10 @@ public class BarController { return vis; } + boolean isTransparentAllowed(WindowState win) { + return win == null || !win.isLetterboxedOverlappingWith(mContentFrame); + } + public boolean setBarShowingLw(final boolean show) { if (mWin == null) return false; if (show && mTransientBarState == TRANSIENT_BAR_HIDING) { @@ -328,6 +344,7 @@ public class BarController { pw.println(StatusBarManager.windowStateToString(mState)); pw.print(prefix); pw.print(" "); pw.print("mTransientBar"); pw.print('='); pw.println(transientBarStateToString(mTransientBarState)); + pw.print(prefix); pw.print(" mContentFrame="); pw.println(mContentFrame); } } diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java index c6ec287d9c6a569233431bcaeab6300c9edc67cc..4aa24465215b1624f553bd4e6e3054b3af608552 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 5728ed7376961ea2dc50479d28f408365bb6236a..4949c0a2af02afe4e212d270e0be4da4a82a0f27 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -666,6 +666,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final Rect mTmpStableFrame = new Rect(); static final Rect mTmpNavigationFrame = new Rect(); static final Rect mTmpOutsetFrame = new Rect(); + private static final Rect mTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect(); private static final Rect mTmpRect = new Rect(); WindowState mTopFullscreenOpaqueWindowState; @@ -1004,7 +1005,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.POLICY_CONTROL), false, this, UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.Global.getUriFor( + resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED), false, this, UserHandle.USER_ALL); updateSettings(); @@ -1462,6 +1463,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); @@ -1761,7 +1765,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } void showGlobalActionsInternal() { - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); } @@ -2704,8 +2707,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; break; case TYPE_DREAM: - // Dreams don't have an app window token and can thus not be letterboxed. - // Hence always let them extend under the cutout. + case TYPE_WALLPAPER: + // Dreams and wallpapers don't have an app window token and can thus not be + // letterboxed. Hence always let them extend under the cutout. attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; break; case TYPE_STATUS_BAR: @@ -3904,6 +3908,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { hideRecentApps(true, false); } + // Handle keyboard layout switching. + // TODO: Deprecate this behavior when we fully migrate to IME subtype-based layout rotation. + if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_SPACE + && ((metaState & KeyEvent.META_CTRL_MASK) != 0)) { + int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1; + mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction); + return -1; + } + // Handle input method switching. if (down && repeatCount == 0 && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH @@ -4505,7 +4518,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { displayWidth, displayHeight); outFrame.intersect(taskBounds); } - outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)); + outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame) + .getDisplayCutout()); return mForceShowSystemBars; } else { if (layoutInScreen) { @@ -4647,7 +4661,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { w.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, df /* overlayFrame */, df /* contentFrame */, df /* visibleFrame */, dcf /* decorFrame */, - df /* stableFrame */, df /* outsetFrame */, displayFrames.mDisplayCutout); + df /* stableFrame */, df /* outsetFrame */, displayFrames.mDisplayCutout, + false /* parentFrameWasClippedByDisplayCutout */); final Rect frame = w.getFrameLw(); if (frame.left <= 0 && frame.top <= 0) { @@ -4710,12 +4725,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */, dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */, - displayFrames.mDisplayCutout); + displayFrames.mDisplayCutout, false /* parentFrameWasClippedByDisplayCutout */); // For layout, the status bar is always at the top with our fixed height. displayFrames.mStable.top = displayFrames.mUnrestricted.top + mStatusBarHeightForRotation[displayFrames.mRotation]; + // Tell the bar controller where the collapsed status bar content is + mTmpRect.set(mStatusBar.getContentFrameLw()); + mTmpRect.intersect(displayFrames.mDisplayCutoutSafe); + mTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset + mTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size + mStatusBarController.setContentFrame(mTmpRect); + boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0; boolean statusBarTranslucent = (sysui & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0; @@ -4771,7 +4793,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // It's a system nav bar or a portrait screen; nav bar goes on bottom. final int top = cutoutSafeUnrestricted.bottom - getNavigationBarHeight(rotation, uiMode); - mTmpNavigationFrame.set(0, top, displayWidth, cutoutSafeUnrestricted.bottom); + mTmpNavigationFrame.set(0, top, displayWidth, displayFrames.mUnrestricted.bottom); displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top; if (transientNavBarShowing) { mNavigationBarController.setBarShowingLw(true); @@ -4794,7 +4816,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Landscape screen; nav bar goes to the right. final int left = cutoutSafeUnrestricted.right - getNavigationBarWidth(rotation, uiMode); - mTmpNavigationFrame.set(left, 0, cutoutSafeUnrestricted.right, displayHeight); + mTmpNavigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight); displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left; if (transientNavBarShowing) { mNavigationBarController.setBarShowingLw(true); @@ -4817,7 +4839,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Seascape screen; nav bar goes to the left. final int right = cutoutSafeUnrestricted.left + getNavigationBarWidth(rotation, uiMode); - mTmpNavigationFrame.set(cutoutSafeUnrestricted.left, 0, right, displayHeight); + mTmpNavigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight); displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right; if (transientNavBarShowing) { mNavigationBarController.setBarShowingLw(true); @@ -4846,8 +4868,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBarLayer = mNavigationBar.getSurfaceLayer(); // And compute the final frame. mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame, - mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf, - mTmpNavigationFrame, mTmpNavigationFrame, displayFrames.mDisplayCutout); + mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe, mTmpNavigationFrame, dcf, + mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe, + displayFrames.mDisplayCutout, false /* parentFrameWasClippedByDisplayCutout */); + mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw()); + if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); return mNavigationBarController.checkHiddenLw(); } @@ -5005,8 +5030,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { df.set(displayFrames.mDock); pf.set(displayFrames.mDock); // IM dock windows layout below the nav bar... - pf.bottom = df.bottom = of.bottom = Math.min(displayFrames.mUnrestricted.bottom, - displayFrames.mDisplayCutoutSafe.bottom); + pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom; // ...with content insets above the nav bar cf.bottom = vf.bottom = displayFrames.mStable.bottom; if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) { @@ -5301,33 +5325,56 @@ public class PhoneWindowManager implements WindowManagerPolicy { vf.set(cf); } } - pf.intersectUnchecked(displayFrames.mDisplayCutoutSafe); } } + boolean parentFrameWasClippedByDisplayCutout = false; final int cutoutMode = attrs.layoutInDisplayCutoutMode; final boolean attachedInParent = attached != null && !layoutInScreen; + final boolean requestedHideNavigation = + (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in // the cutout safe zone. if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) { - final Rect displayCutoutSafeExceptMaybeTop = mTmpRect; - displayCutoutSafeExceptMaybeTop.set(displayFrames.mDisplayCutoutSafe); + final Rect displayCutoutSafeExceptMaybeBars = mTmpDisplayCutoutSafeExceptMaybeBarsRect; + displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe); if (layoutInScreen && layoutInsetDecor && !requestedFullscreen && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) { // At the top we have the status bar, so apps that are // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN // already expect that there's an inset there and we don't need to exclude // the window from that area. - displayCutoutSafeExceptMaybeTop.top = Integer.MIN_VALUE; + displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE; } - // Windows that are attached to a parent and laid out in said parent are already - // avoidingthe cutout according to that parent and don't need to be further constrained. + if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation + && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) { + // Same for the navigation bar. + switch (mNavigationBarPosition) { + case NAV_BAR_BOTTOM: + displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; + break; + case NAV_BAR_RIGHT: + displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE; + break; + case NAV_BAR_LEFT: + displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE; + break; + } + } + if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) { + // The IME can always extend under the bottom cutout if the navbar is there. + displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; + } + // Windows that are attached to a parent and laid out in said parent already avoid + // the cutout according to that parent and don't need to be further constrained. if (!attachedInParent) { - pf.intersectUnchecked(displayCutoutSafeExceptMaybeTop); + mTmpRect.set(pf); + pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars); + parentFrameWasClippedByDisplayCutout |= !mTmpRect.equals(pf); } - // Make sure that NO_LIMITS windows clipped to the display don't extend into the display - // don't extend under the cutout. - df.intersectUnchecked(displayCutoutSafeExceptMaybeTop); + // Make sure that NO_LIMITS windows clipped to the display don't extend under the + // cutout. + df.intersectUnchecked(displayCutoutSafeExceptMaybeBars); } // Content should never appear in the cutout. @@ -5381,7 +5428,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { + " sf=" + sf.toShortString() + " osf=" + (osf == null ? "null" : osf.toShortString())); - win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout); + win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout, + parentFrameWasClippedByDisplayCutout); // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. @@ -8015,11 +8063,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the top fullscreen-or-dimming window is also the top fullscreen, respect // its light flag. vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - if (!statusColorWin.isLetterboxedForDisplayCutoutLw()) { - // Only allow white status bar if the window was not letterboxed. - vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null) - & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } + vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null) + & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; } else if (statusColorWin != null && statusColorWin.isDimming()) { // Otherwise if it's dimming, clear the light flag. vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; @@ -8087,15 +8132,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return vis; } - private boolean drawsSystemBarBackground(WindowState win) { - return win == null || (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; - } - - private boolean forcesDrawStatusBarBackground(WindowState win) { - return win == null || (win.getAttrs().privateFlags - & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0; - } - private int updateSystemBarsLw(WindowState win, int oldVis, int vis) { final boolean dockedStackVisible = mWindowManagerInternal.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); @@ -8119,13 +8155,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mTopDockedOpaqueWindowState, 0, 0); final boolean fullscreenDrawsStatusBarBackground = - (drawsSystemBarBackground(mTopFullscreenOpaqueWindowState) - && (vis & View.STATUS_BAR_TRANSLUCENT) == 0) - || forcesDrawStatusBarBackground(mTopFullscreenOpaqueWindowState); + drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState); final boolean dockedDrawsStatusBarBackground = - (drawsSystemBarBackground(mTopDockedOpaqueWindowState) - && (dockedVis & View.STATUS_BAR_TRANSLUCENT) == 0) - || forcesDrawStatusBarBackground(mTopDockedOpaqueWindowState); + drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState); // prevent status bar interaction from clearing certain flags int type = win.getAttrs().type; @@ -8228,6 +8260,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { return vis; } + private boolean drawsStatusBarBackground(int vis, WindowState win) { + if (!mStatusBarController.isTransparentAllowed(win)) { + return false; + } + if (win == null) { + return true; + } + + final boolean drawsSystemBars = + (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; + final boolean forceDrawsSystemBars = + (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0; + + return forceDrawsSystemBars || drawsSystemBars && (vis & View.STATUS_BAR_TRANSLUCENT) == 0; + } + /** * @return the current visibility flags with the nav-bar opacity related flags toggled based * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}. @@ -8801,4 +8849,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 cd6ff30efd13634d72e52770378e0fa207dfe7a5..6674e185118ad030f4468e879f3a966ed793e062 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; @@ -93,6 +94,7 @@ import android.view.animation.Animation; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; import com.android.server.wm.DisplayFrames; +import com.android.server.wm.utils.WmDisplayCutout; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -217,11 +219,14 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @param stableFrame The frame around which stable system decoration is positioned. * @param outsetFrame The frame that includes areas that aren't part of the surface but we * want to treat them as such. - * @param displayCutout the display displayCutout + * @param displayCutout the display cutout + * @param parentFrameWasClippedByDisplayCutout true if the parent frame would have been + * different if there was no display cutout. */ public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, - Rect stableFrame, @Nullable Rect outsetFrame, DisplayCutout displayCutout); + Rect stableFrame, @Nullable Rect outsetFrame, WmDisplayCutout displayCutout, + boolean parentFrameWasClippedByDisplayCutout); /** * Retrieve the current frame of the window that has been assigned by @@ -445,6 +450,14 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { return false; } + /** + * Returns true if the window has a letterbox and any part of that letterbox overlaps with + * the given {@code rect}. + */ + default boolean isLetterboxedOverlappingWith(Rect rect) { + return false; + } + /** @return the current windowing mode of this window. */ int getWindowingMode(); @@ -544,6 +557,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { */ public int getCameraLensCoverState(); + /** + * Switch the keyboard layout for the given device. + * Direction should be +1 or -1 to go to the next or previous keyboard layout. + */ + public void switchKeyboardLayout(int deviceId, int direction); + /** * Switch the input method, to be precise, input method subtype. * @@ -1724,4 +1743,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/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java index 16336b308dbcfb40e64c019eafa6f5b71e793d3e..483f974ab8b6ffc1f383d3d87f247b354629ad5f 100644 --- a/services/core/java/com/android/server/power/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java @@ -69,6 +69,7 @@ public class BatterySaverPolicy extends ContentObserver { private static final String KEY_FORCE_BACKGROUND_CHECK = "force_background_check"; private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled"; private static final String KEY_AOD_DISABLED = "aod_disabled"; + private static final String KEY_SEND_TRON_LOG = "send_tron_log"; private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i"; private static final String KEY_CPU_FREQ_NONINTERACTIVE = "cpufreq-n"; @@ -212,6 +213,12 @@ public class BatterySaverPolicy extends ContentObserver { @GuardedBy("mLock") private boolean mAodDisabled; + /** + * Whether BatterySavingStats should send tron events. + */ + @GuardedBy("mLock") + private boolean mSendTronLog; + @GuardedBy("mLock") private Context mContext; @@ -347,6 +354,7 @@ public class BatterySaverPolicy extends ContentObserver { mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true); mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true); mAodDisabled = parser.getBoolean(KEY_AOD_DISABLED, true); + mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, true); // Get default value from Settings.Secure final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE, @@ -384,10 +392,13 @@ public class BatterySaverPolicy extends ContentObserver { if (mLaunchBoostDisabled) sb.append("l"); if (mOptionalSensorsDisabled) sb.append("S"); if (mAodDisabled) sb.append("o"); + if (mSendTronLog) sb.append("t"); sb.append(mGpsMode); mEventLogKeys = sb.toString(); + + BatterySavingStats.getInstance().setSendTronLog(mSendTronLog); } /** @@ -483,7 +494,10 @@ public class BatterySaverPolicy extends ContentObserver { public void dump(PrintWriter pw) { synchronized (mLock) { pw.println(); - pw.println("Battery saver policy"); + BatterySavingStats.getInstance().dump(pw, ""); + + pw.println(); + pw.println("Battery saver policy (*NOTE* they only apply when battery saver is ON):"); pw.println(" Settings: " + Settings.Global.BATTERY_SAVER_CONSTANTS); pw.println(" value: " + mSettings); pw.println(" Settings: " + mDeviceSpecificSettingsSource); @@ -504,6 +518,7 @@ public class BatterySaverPolicy extends ContentObserver { pw.println(" " + KEY_FORCE_BACKGROUND_CHECK + "=" + mForceBackgroundCheck); pw.println(" " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled); pw.println(" " + KEY_AOD_DISABLED + "=" + mAodDisabled); + pw.println(" " + KEY_SEND_TRON_LOG + "=" + mSendTronLog); pw.println(); pw.print(" Interactive File values:\n"); @@ -512,9 +527,6 @@ public class BatterySaverPolicy extends ContentObserver { pw.print(" Noninteractive File values:\n"); dumpMap(pw, " ", mFilesForNoninteractive); - pw.println(); - pw.println(); - BatterySavingStats.getInstance().dump(pw, " "); } } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index b729b6a0f47f74bf50a0078c6817e0aa0b25559b..285532aef71ff48a69b969f010e01327f24ed703 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/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index d7d39226722cd78c27e9e74d26a35227d5b47eac..40a94a71792afd0d5f2ec4aa9598e4746668a193 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -69,7 +69,6 @@ import android.service.dreams.DreamManagerInternal; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; import android.util.KeyValueListParser; -import android.util.MathUtils; import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseArray; @@ -408,7 +407,7 @@ public final class PowerManagerService extends SystemService private boolean mDreamsActivateOnDockSetting; // True if doze should not be started until after the screen off transition. - private boolean mDozeAfterScreenOffConfig; + private boolean mDozeAfterScreenOff; // The minimum screen off timeout, in milliseconds. private long mMinimumScreenOffTimeoutConfig; @@ -487,6 +486,9 @@ public final class PowerManagerService extends SystemService // The screen brightness to use while dozing. private int mDozeScreenBrightnessOverrideFromDreamManager = PowerManager.BRIGHTNESS_DEFAULT; + // Keep display state when dozing. + private boolean mDrawWakeLockOverrideFromSidekick; + // Time when we last logged a warning about calling userActivity() without permission. private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE; @@ -893,7 +895,7 @@ public final class PowerManagerService extends SystemService com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenNotPowered); mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger( com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff); - mDozeAfterScreenOffConfig = resources.getBoolean( + mDozeAfterScreenOff = resources.getBoolean( com.android.internal.R.bool.config_dozeAfterScreenOff); mMinimumScreenOffTimeoutConfig = resources.getInteger( com.android.internal.R.integer.config_minimumScreenOffTimeout); @@ -2423,7 +2425,8 @@ public final class PowerManagerService extends SystemService if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) { mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager; - if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) { + if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0 + && !mDrawWakeLockOverrideFromSidekick) { if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) { mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE; } @@ -2503,7 +2506,7 @@ public final class PowerManagerService extends SystemService if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) { return DisplayPowerRequest.POLICY_DOZE; } - if (mDozeAfterScreenOffConfig) { + if (mDozeAfterScreenOff) { return DisplayPowerRequest.POLICY_OFF; } // Fall through and preserve the current screen policy if not configured to @@ -3090,6 +3093,12 @@ public final class PowerManagerService extends SystemService light.setFlashing(color, Light.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0); } + private void setDozeAfterScreenOffInternal(boolean on) { + synchronized (mLock) { + mDozeAfterScreenOff = on; + } + } + private void boostScreenBrightnessInternal(long eventTime, int uid) { synchronized (mLock) { if (!mSystemReady || mWakefulness == WAKEFULNESS_ASLEEP @@ -3176,6 +3185,16 @@ public final class PowerManagerService extends SystemService } } + private void setDrawWakeLockOverrideFromSidekickInternal(boolean keepState) { + synchronized (mLock) { + if (mDrawWakeLockOverrideFromSidekick != keepState) { + mDrawWakeLockOverrideFromSidekick = keepState; + mDirty |= DIRTY_SETTINGS; + updatePowerStateLocked(); + } + } + } + @VisibleForTesting void setVrModeEnabled(boolean enabled) { mIsVrModeEnabled = enabled; @@ -3358,7 +3377,7 @@ public final class PowerManagerService extends SystemService pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting); pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting); pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting); - pw.println(" mDozeAfterScreenOffConfig=" + mDozeAfterScreenOffConfig); + pw.println(" mDozeAfterScreenOff=" + mDozeAfterScreenOff); pw.println(" mLowPowerModeSetting=" + mLowPowerModeSetting); pw.println(" mAutoLowPowerModeConfigured=" + mAutoLowPowerModeConfigured); pw.println(" mAutoLowPowerModeSnoozing=" + mAutoLowPowerModeSnoozing); @@ -3381,6 +3400,7 @@ public final class PowerManagerService extends SystemService + mUserInactiveOverrideFromWindowManager); pw.println(" mDozeScreenStateOverrideFromDreamManager=" + mDozeScreenStateOverrideFromDreamManager); + pw.println(" mDrawWakeLockOverrideFromSidekick=" + mDrawWakeLockOverrideFromSidekick); pw.println(" mDozeScreenBrightnessOverrideFromDreamManager=" + mDozeScreenBrightnessOverrideFromDreamManager); pw.println(" mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum); @@ -3641,7 +3661,7 @@ public final class PowerManagerService extends SystemService mDreamsActivateOnDockSetting); proto.write( PowerServiceSettingsAndConfigurationDumpProto.IS_DOZE_AFTER_SCREEN_OFF_CONFIG, - mDozeAfterScreenOffConfig); + mDozeAfterScreenOff); proto.write( PowerServiceSettingsAndConfigurationDumpProto.IS_LOW_POWER_MODE_SETTING, mLowPowerModeSetting); @@ -3715,6 +3735,10 @@ public final class PowerManagerService extends SystemService PowerServiceSettingsAndConfigurationDumpProto .DOZE_SCREEN_STATE_OVERRIDE_FROM_DREAM_MANAGER, mDozeScreenStateOverrideFromDreamManager); + proto.write( + PowerServiceSettingsAndConfigurationDumpProto + .DRAW_WAKE_LOCK_OVERRIDE_FROM_SIDEKICK, + mDrawWakeLockOverrideFromSidekick); proto.write( PowerServiceSettingsAndConfigurationDumpProto .DOZED_SCREEN_BRIGHTNESS_OVERRIDE_FROM_DREAM_MANAGER, @@ -4583,6 +4607,19 @@ public final class PowerManagerService extends SystemService } } + @Override // Binder call + public void setDozeAfterScreenOff(boolean on) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + + final long ident = Binder.clearCallingIdentity(); + try { + setDozeAfterScreenOffInternal(on); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + @Override // Binder call public void boostScreenBrightness(long eventTime) { if (eventTime > SystemClock.uptimeMillis()) { @@ -4702,6 +4739,11 @@ public final class PowerManagerService extends SystemService setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis); } + @Override + public void setDrawWakeLockOverrideFromSidekick(boolean keepState) { + setDrawWakeLockOverrideFromSidekickInternal(keepState); + } + @Override public void setMaximumScreenOffTimeoutFromDeviceAdmin(@UserIdInt int userId, long timeMs) { setMaximumScreenOffTimeoutFromDeviceAdminInternal(userId, timeMs); diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java index 5d76329eb8a140e0ca89dfddd835aa4eb25e89df..05549e70cd1cab139759e4ad24f309a87d42a6f6 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java @@ -20,6 +20,7 @@ import android.os.BatteryManagerInternal; import android.os.SystemClock; import android.util.ArrayMap; import android.util.Slog; +import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -31,6 +32,8 @@ import com.android.server.LocalServices; import com.android.server.power.BatterySaverPolicy; import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Date; /** * This class keeps track of battery drain rate. @@ -46,9 +49,6 @@ public class BatterySavingStats { private static final boolean DEBUG = BatterySaverPolicy.DEBUG; - @VisibleForTesting - static final boolean SEND_TRON_EVENTS = true; - private final Object mLock = new Object(); /** Whether battery saver is on or off. */ @@ -159,8 +159,24 @@ public class BatterySavingStats { @GuardedBy("mLock") final ArrayMap mStats = new ArrayMap<>(); + @GuardedBy("mLock") + private int mBatterySaverEnabledCount = 0; + + @GuardedBy("mLock") + private boolean mIsBatterySaverEnabled; + + @GuardedBy("mLock") + private long mLastBatterySaverEnabledTime = 0; + + @GuardedBy("mLock") + private long mLastBatterySaverDisabledTime = 0; + private final MetricsLoggerHelper mMetricsLoggerHelper = new MetricsLoggerHelper(); + @VisibleForTesting + @GuardedBy("mLock") + private boolean mSendTronLog; + /** * Don't call it directly -- use {@link #getInstance()}. Not private for testing. * @param metricsLogger @@ -178,6 +194,12 @@ public class BatterySavingStats { return sInstance; } + public void setSendTronLog(boolean send) { + synchronized (mLock) { + mSendTronLog = send; + } + } + private BatteryManagerInternal getBatteryManagerInternal() { if (mBatteryManagerInternal == null) { mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class); @@ -291,9 +313,23 @@ public class BatterySavingStats { final int batteryLevel = injectBatteryLevel(); final int batteryPercent = injectBatteryPercent(); + final boolean oldBatterySaverEnabled = + BatterySaverState.fromIndex(mCurrentState) != BatterySaverState.OFF; + final boolean newBatterySaverEnabled = + BatterySaverState.fromIndex(newState) != BatterySaverState.OFF; + if (oldBatterySaverEnabled != newBatterySaverEnabled) { + mIsBatterySaverEnabled = newBatterySaverEnabled; + if (newBatterySaverEnabled) { + mBatterySaverEnabledCount++; + mLastBatterySaverEnabledTime = injectCurrentTime(); + } else { + mLastBatterySaverDisabledTime = injectCurrentTime(); + } + } + endLastStateLocked(now, batteryLevel, batteryPercent); startNewStateLocked(newState, now, batteryLevel, batteryPercent); - mMetricsLoggerHelper.transitionState(newState, now, batteryLevel, batteryPercent); + mMetricsLoggerHelper.transitionStateLocked(newState, now, batteryLevel, batteryPercent); } @GuardedBy("mLock") @@ -358,12 +394,49 @@ public class BatterySavingStats { public void dump(PrintWriter pw, String indent) { synchronized (mLock) { pw.print(indent); - pw.println("Battery Saving Stats:"); + pw.println("Battery saving stats:"); indent = indent + " "; + final long now = System.currentTimeMillis(); + final long nowElapsed = injectCurrentTime(); + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + + pw.print(indent); + pw.print("Battery Saver is currently: "); + pw.println(mIsBatterySaverEnabled ? "ON" : "OFF"); + if (mLastBatterySaverEnabledTime > 0) { + pw.print(indent); + pw.print(" "); + pw.print("Last ON time: "); + pw.print(sdf.format(new Date(now - nowElapsed + mLastBatterySaverEnabledTime))); + pw.print(" "); + TimeUtils.formatDuration(mLastBatterySaverEnabledTime, nowElapsed, pw); + pw.println(); + } + + if (mLastBatterySaverDisabledTime > 0) { + pw.print(indent); + pw.print(" "); + pw.print("Last OFF time: "); + pw.print(sdf.format(new Date(now - nowElapsed + mLastBatterySaverDisabledTime))); + pw.print(" "); + TimeUtils.formatDuration(mLastBatterySaverDisabledTime, nowElapsed, pw); + pw.println(); + } + pw.print(indent); - pw.println("Battery Saver: w/Off w/On"); + pw.print(" "); + pw.print("Times enabled: "); + pw.println(mBatterySaverEnabledCount); + + pw.println(); + + pw.print(indent); + pw.println("Drain stats:"); + + pw.print(indent); + pw.println(" Battery saver OFF ON"); dumpLineLocked(pw, indent, InteractiveState.NON_INTERACTIVE, "NonIntr", DozeState.NOT_DOZING, "NonDoze"); dumpLineLocked(pw, indent, InteractiveState.INTERACTIVE, " Intr", @@ -378,8 +451,6 @@ public class BatterySavingStats { DozeState.LIGHT, "Light "); dumpLineLocked(pw, indent, InteractiveState.INTERACTIVE, " Intr", DozeState.LIGHT, " "); - - pw.println(); } } @@ -395,7 +466,7 @@ public class BatterySavingStats { final Stat offStat = getStat(BatterySaverState.OFF, interactiveState, dozeState); final Stat onStat = getStat(BatterySaverState.ON, interactiveState, dozeState); - pw.println(String.format("%6dm %6dmA (%3d%%) %8.1fmA/h %6dm %6dmA (%3d%%) %8.1fmA/h", + pw.println(String.format("%6dm %6dmAh(%3d%%) %8.1fmAh/h %6dm %6dmAh(%3d%%) %8.1fmAh/h", offStat.totalMinutes(), offStat.totalBatteryDrain / 1000, offStat.totalBatteryDrainPercent, @@ -417,7 +488,8 @@ public class BatterySavingStats { (BatterySaverState.MASK << BatterySaverState.SHIFT) | (InteractiveState.MASK << InteractiveState.SHIFT); - public void transitionState(int newState, long now, int batteryLevel, int batteryPercent) { + public void transitionStateLocked( + int newState, long now, int batteryLevel, int batteryPercent) { final boolean stateChanging = ((mLastState >= 0) ^ (newState >= 0)) || (((mLastState ^ newState) & STATE_CHANGE_DETECT_MASK) != 0); @@ -425,7 +497,7 @@ public class BatterySavingStats { if (mLastState >= 0) { final long deltaTime = now - mStartTime; - report(mLastState, deltaTime, mStartBatteryLevel, mStartPercent, + reportLocked(mLastState, deltaTime, mStartBatteryLevel, mStartPercent, batteryLevel, batteryPercent); } mStartTime = now; @@ -435,10 +507,10 @@ public class BatterySavingStats { mLastState = newState; } - void report(int state, long deltaTimeMs, + void reportLocked(int state, long deltaTimeMs, int startBatteryLevelUa, int startBatteryLevelPercent, int endBatteryLevelUa, int endBatteryLevelPercent) { - if (!SEND_TRON_EVENTS) { + if (!mSendTronLog) { return; } final boolean batterySaverOn = diff --git a/services/core/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java index 6bacdfdafbda1472addcaa3cada4072a8c5ecd0a..8af76a17f08434d72e08d7b09719a8efb1b89ed8 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 getSearchablesList() { - ArrayList result = new ArrayList(mSearchablesList); - return result; + return createFilterdSearchableInfoList(mSearchablesList); } /** * Returns a list of the searchable activities that can be included in global search. */ public synchronized ArrayList getSearchablesInGlobalSearchList() { - return new ArrayList(mSearchablesInGlobalSearchList); + return createFilterdSearchableInfoList(mSearchablesInGlobalSearchList); } /** * Returns a list of activities that handle the global search intent. */ public synchronized ArrayList getGlobalSearchActivities() { - return new ArrayList(mGlobalSearchActivities); + return createFilterdResolveInfoList(mGlobalSearchActivities); + } + + private ArrayList createFilterdSearchableInfoList(List list) { + if (list == null) { + return null; + } + final ArrayList 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 createFilterdResolveInfoList(List list) { + if (list == null) { + return null; + } + final ArrayList 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 f9a4ea211f0738601d07406b65ec057d6e823f14..4e7fb969f39830320979ea2de7b7a1142a955d34 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 mPinnedPkgs = new ArraySet<>(); @GuardedBy("mLock") private final ArrayMap 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 51e4709aa7c73147ca5b7552b8e693bbb4259b20..a7dfd35acf1b5402f5ee6bc9d469a50529adc035 100644 --- a/services/core/java/com/android/server/slice/SliceManagerService.java +++ b/services/core/java/com/android/server/slice/SliceManagerService.java @@ -148,12 +148,26 @@ public class SliceManagerService extends ISliceManager.Stub { } /// ----- ISliceManager stuff ----- + @Override + public Uri[] getPinnedSlices(String pkg) { + verifyCaller(pkg); + ArrayList 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/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 64a2570c563151e1deb9290aba8036fe640d1854..74c5ee9c352044e883d36193a2ad652f91f1826b 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -73,6 +73,7 @@ import com.android.server.SystemService; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; @@ -176,7 +177,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader mKernelUidCpuFreqTimeReader.setThrottleInterval(0); long[] freqs = mKernelUidCpuFreqTimeReader.readFreqs(powerProfile); - mKernelUidCpuFreqTimeReader.setReadBinary(true); mKernelUidCpuClusterTimeReader.setThrottleInterval(0); mKernelUidCpuActiveTimeReader.setThrottleInterval(0); } @@ -196,6 +196,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { @Override public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey, long subscriptionId, long subscriptionRuleId, + String[] cookies, StatsDimensionsValue dimensionsValue) { enforceCallingPermission(); IntentSender intentSender = new IntentSender(intentSenderBinder); @@ -205,10 +206,17 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId) .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId) .putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue); + + ArrayList cookieList = new ArrayList<>(cookies.length); + for (String cookie : cookies) { cookieList.add(cookie); } + intent.putStringArrayListExtra( + StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES, cookieList); + if (DEBUG) { - Slog.d(TAG, String.format("Statsd sendSubscriberBroadcast with params {%d %d %d %d %s}", - configUid, configKey, subscriptionId, - subscriptionRuleId, dimensionsValue)); + Slog.d(TAG, String.format( + "Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}", + configUid, configKey, subscriptionId, subscriptionRuleId, + Arrays.toString(cookies), dimensionsValue)); } try { intentSender.sendIntent(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null); @@ -278,7 +286,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { return; // Keep only replacing or normal add and remove. } - Slog.i(TAG, "StatsCompanionService noticed an app was updated."); + if (DEBUG) Slog.d(TAG, "StatsCompanionService noticed an app was updated."); synchronized (sStatsdLock) { if (sStatsd == null) { Slog.w(TAG, "Could not access statsd to inform it of an app update"); @@ -711,11 +719,13 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { long elapsedNanos = SystemClock.elapsedRealtimeNanos(); mKernelUidCpuFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> { for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) { - StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3); - e.writeInt(uid); - e.writeInt(freqIndex); - e.writeLong(cpuFreqTimeMs[freqIndex]); - pulledData.add(e); + if(cpuFreqTimeMs[freqIndex] != 0) { + StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3); + e.writeInt(uid); + e.writeInt(freqIndex); + e.writeLong(cpuFreqTimeMs[freqIndex]); + pulledData.add(e); + } } }); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 59fce64b2f2cde9dc563d0497537fedc990c8311..0678d0805b82e4d8215a5b7d562ac888cdf9a8fd 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -629,7 +629,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub { */ @Override public void disable2ForUser(int what, IBinder token, String pkg, int userId) { - enforceStatusBarService(); + enforceStatusBar(); synchronized (mLock) { disableLocked(userId, what, token, pkg, 2); diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index 0ac853b030e1216e1f560975adf9a1fc6a2d90c8..6df7092cf811a631f223ca8d809220e55060f1d7 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -17,31 +17,38 @@ package com.android.server.textclassifier; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; -import android.util.Slog; -import android.service.textclassifier.ITextClassifierService; +import android.os.UserHandle; import android.service.textclassifier.ITextClassificationCallback; +import android.service.textclassifier.ITextClassifierService; import android.service.textclassifier.ITextLinksCallback; import android.service.textclassifier.ITextSelectionCallback; import android.service.textclassifier.TextClassifierService; +import android.util.Slog; +import android.util.SparseArray; +import android.view.textclassifier.SelectionEvent; import android.view.textclassifier.TextClassification; import android.view.textclassifier.TextClassifier; import android.view.textclassifier.TextLinks; import android.view.textclassifier.TextSelection; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.FunctionalUtils; +import com.android.internal.util.FunctionalUtils.ThrowingRunnable; import com.android.internal.util.Preconditions; import com.android.server.SystemService; -import java.util.LinkedList; +import java.util.ArrayDeque; import java.util.Queue; -import java.util.concurrent.Callable; /** * A manager for TextClassifier services. @@ -71,58 +78,44 @@ public final class TextClassificationManagerService extends ITextClassifierServi Slog.e(LOG_TAG, "Could not start the TextClassificationManagerService.", t); } } - } - private final Context mContext; - private final Intent mServiceIntent; - private final ServiceConnection mConnection; - private final Object mLock; - @GuardedBy("mLock") - private final Queue mPendingRequests; + @Override + public void onStartUser(int userId) { + processAnyPendingWork(userId); + } - @GuardedBy("mLock") - private ITextClassifierService mService; - @GuardedBy("mLock") - private boolean mBinding; + @Override + public void onUnlockUser(int userId) { + // Rebind if we failed earlier due to locked encrypted user + processAnyPendingWork(userId); + } - private TextClassificationManagerService(Context context) { - mContext = Preconditions.checkNotNull(context); - mServiceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE) - .setComponent(TextClassifierService.getServiceComponentName(mContext)); - mConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - synchronized (mLock) { - mService = ITextClassifierService.Stub.asInterface(service); - setBindingLocked(false); - handlePendingRequestsLocked(); - } + private void processAnyPendingWork(int userId) { + synchronized (mManagerService.mLock) { + mManagerService.getUserStateLocked(userId).bindIfHasPendingRequestsLocked(); } + } - @Override - public void onServiceDisconnected(ComponentName name) { - cleanupService(); + @Override + public void onStopUser(int userId) { + synchronized (mManagerService.mLock) { + UserState userState = mManagerService.peekUserStateLocked(userId); + if (userState != null) { + userState.mConnection.cleanupService(); + mManagerService.mUserStates.remove(userId); + } } + } - @Override - public void onBindingDied(ComponentName name) { - cleanupService(); - } + } - @Override - public void onNullBinding(ComponentName name) { - cleanupService(); - } + private final Context mContext; + private final Object mLock; + @GuardedBy("mLock") + final SparseArray mUserStates = new SparseArray<>(); - private void cleanupService() { - synchronized (mLock) { - mService = null; - setBindingLocked(false); - handlePendingRequestsLocked(); - } - } - }; - mPendingRequests = new LinkedList<>(); + private TextClassificationManagerService(Context context) { + mContext = Preconditions.checkNotNull(context); mLock = new Object(); } @@ -131,30 +124,20 @@ public final class TextClassificationManagerService extends ITextClassifierServi CharSequence text, int selectionStartIndex, int selectionEndIndex, TextSelection.Options options, ITextSelectionCallback callback) throws RemoteException { - // TODO(b/72481438): All remote calls need to take userId. validateInput(text, selectionStartIndex, selectionEndIndex, callback); - if (!bind()) { - callback.onFailure(); - return; - } - synchronized (mLock) { - if (isBoundLocked()) { - mService.onSuggestSelection( + UserState userState = getCallingUserStateLocked(); + if (!userState.bindLocked()) { + callback.onFailure(); + } else if (userState.isBoundLocked()) { + userState.mService.onSuggestSelection( text, selectionStartIndex, selectionEndIndex, options, callback); } else { - final Callable request = () -> { - onSuggestSelection( - text, selectionStartIndex, selectionEndIndex, - options, callback); - return null; - }; - final Callable onServiceFailure = () -> { - callback.onFailure(); - return null; - }; - enqueueRequestLocked(request, onServiceFailure, callback.asBinder()); + userState.mPendingRequests.add(new PendingRequest( + () -> onSuggestSelection( + text, selectionStartIndex, selectionEndIndex, options, callback), + callback::onFailure, callback.asBinder(), this, userState)); } } } @@ -166,24 +149,16 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { validateInput(text, startIndex, endIndex, callback); - if (!bind()) { - callback.onFailure(); - return; - } - synchronized (mLock) { - if (isBoundLocked()) { - mService.onClassifyText(text, startIndex, endIndex, options, callback); + UserState userState = getCallingUserStateLocked(); + if (!userState.bindLocked()) { + callback.onFailure(); + } else if (userState.isBoundLocked()) { + userState.mService.onClassifyText(text, startIndex, endIndex, options, callback); } else { - final Callable request = () -> { - onClassifyText(text, startIndex, endIndex, options, callback); - return null; - }; - final Callable onServiceFailure = () -> { - callback.onFailure(); - return null; - }; - enqueueRequestLocked(request, onServiceFailure, callback.asBinder()); + userState.mPendingRequests.add(new PendingRequest( + () -> onClassifyText(text, startIndex, endIndex, options, callback), + callback::onFailure, callback.asBinder(), this, userState)); } } } @@ -194,140 +169,94 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { validateInput(text, callback); - if (!bind()) { - callback.onFailure(); - return; - } - synchronized (mLock) { - if (isBoundLocked()) { - mService.onGenerateLinks(text, options, callback); + UserState userState = getCallingUserStateLocked(); + if (!userState.bindLocked()) { + callback.onFailure(); + } else if (userState.isBoundLocked()) { + userState.mService.onGenerateLinks(text, options, callback); } else { - final Callable request = () -> { - onGenerateLinks(text, options, callback); - return null; - }; - final Callable onServiceFailure = () -> { - callback.onFailure(); - return null; - }; - enqueueRequestLocked(request, onServiceFailure, callback.asBinder()); + userState.mPendingRequests.add(new PendingRequest( + () -> onGenerateLinks(text, options, callback), + callback::onFailure, callback.asBinder(), this, userState)); } } } - /** - * @return true if the service is bound or in the process of being bound. - * Returns false otherwise. - */ - private boolean bind() { - synchronized (mLock) { - if (isBoundLocked() || isBindingLocked()) { - return true; - } + @Override + public void onSelectionEvent(SelectionEvent event) throws RemoteException { + validateInput(event, mContext); - // TODO: Handle bind timeout. - final boolean willBind; - final long identity = Binder.clearCallingIdentity(); - try { - Slog.d(LOG_TAG, "Binding to " + mServiceIntent.getComponent()); - willBind = mContext.bindServiceAsUser( - mServiceIntent, mConnection, - Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, - Binder.getCallingUserHandle()); - setBindingLocked(willBind); - } finally { - Binder.restoreCallingIdentity(identity); + synchronized (mLock) { + UserState userState = getCallingUserStateLocked(); + if (userState.isBoundLocked()) { + userState.mService.onSelectionEvent(event); + } else { + userState.mPendingRequests.add(new PendingRequest( + () -> onSelectionEvent(event), + null /* onServiceFailure */, null /* binder */, this, userState)); } - return willBind; } } - @GuardedBy("mLock") - private boolean isBoundLocked() { - return mService != null; - } - - @GuardedBy("mLock") - private boolean isBindingLocked() { - return mBinding; - } - - @GuardedBy("mLock") - private void setBindingLocked(boolean binding) { - mBinding = binding; + private UserState getCallingUserStateLocked() { + return getUserStateLocked(UserHandle.getCallingUserId()); } - @GuardedBy("mLock") - private void enqueueRequestLocked( - Callable request, Callable onServiceFailure, IBinder binder) { - mPendingRequests.add(new PendingRequest(request, onServiceFailure, binder)); + private UserState getUserStateLocked(int userId) { + UserState result = mUserStates.get(userId); + if (result == null) { + result = new UserState(userId, mContext, mLock); + mUserStates.put(userId, result); + } + return result; } - @GuardedBy("mLock") - private void handlePendingRequestsLocked() { - // TODO(b/72481146): Implement PendingRequest similar to that in RemoteFillService. - final PendingRequest[] pendingRequests = - mPendingRequests.toArray(new PendingRequest[mPendingRequests.size()]); - for (PendingRequest pendingRequest : pendingRequests) { - if (isBoundLocked()) { - pendingRequest.executeLocked(); - } else { - pendingRequest.notifyServiceFailureLocked(); - } - } + UserState peekUserStateLocked(int userId) { + return mUserStates.get(userId); } - private final class PendingRequest implements IBinder.DeathRecipient { + private static final class PendingRequest implements IBinder.DeathRecipient { - private final Callable mRequest; - private final Callable mOnServiceFailure; - private final IBinder mBinder; + @Nullable private final IBinder mBinder; + @NonNull private final Runnable mRequest; + @Nullable private final Runnable mOnServiceFailure; + @GuardedBy("mLock") + @NonNull private final UserState mOwningUser; + @NonNull private final TextClassificationManagerService mService; /** * Initializes a new pending request. - * * @param request action to perform when the service is bound * @param onServiceFailure action to perform when the service dies or disconnects * @param binder binder to the process that made this pending request + * @param service + * @param owningUser */ PendingRequest( - @NonNull Callable request, @NonNull Callable onServiceFailure, - @NonNull IBinder binder) { - mRequest = Preconditions.checkNotNull(request); - mOnServiceFailure = Preconditions.checkNotNull(onServiceFailure); - mBinder = Preconditions.checkNotNull(binder); - try { - mBinder.linkToDeath(this, 0); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - - @GuardedBy("mLock") - void executeLocked() { - removeLocked(); - try { - mRequest.call(); - } catch (Exception e) { - Slog.d(LOG_TAG, "Error handling pending request: " + e.getMessage()); - } - } - - @GuardedBy("mLock") - void notifyServiceFailureLocked() { - removeLocked(); - try { - mOnServiceFailure.call(); - } catch (Exception e) { - Slog.d(LOG_TAG, "Error notifying callback of service failure: " - + e.getMessage()); + @NonNull ThrowingRunnable request, @Nullable ThrowingRunnable onServiceFailure, + @Nullable IBinder binder, + TextClassificationManagerService service, + UserState owningUser) { + mRequest = + logOnFailure(Preconditions.checkNotNull(request), "handling pending request"); + mOnServiceFailure = + logOnFailure(onServiceFailure, "notifying callback of service failure"); + mBinder = binder; + mService = service; + mOwningUser = owningUser; + if (mBinder != null) { + try { + mBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + e.printStackTrace(); + } } } @Override public void binderDied() { - synchronized (mLock) { + synchronized (mService.mLock) { // No need to handle this pending request anymore. Remove. removeLocked(); } @@ -335,11 +264,19 @@ public final class TextClassificationManagerService extends ITextClassifierServi @GuardedBy("mLock") private void removeLocked() { - mPendingRequests.remove(this); - mBinder.unlinkToDeath(this, 0); + mOwningUser.mPendingRequests.remove(this); + if (mBinder != null) { + mBinder.unlinkToDeath(this, 0); + } } } + private static Runnable logOnFailure(@Nullable ThrowingRunnable r, String opDesc) { + if (r == null) return null; + return FunctionalUtils.handleExceptions(r, + e -> Slog.d(LOG_TAG, "Error " + opDesc + ": " + e.getMessage())); + } + private static void validateInput( CharSequence text, int startIndex, int endIndex, Object callback) throws RemoteException { @@ -359,4 +296,131 @@ public final class TextClassificationManagerService extends ITextClassifierServi throw new RemoteException(e.getMessage()); } } + + private static void validateInput(SelectionEvent event, Context context) + throws RemoteException { + try { + final int uid = context.getPackageManager() + .getPackageUid(event.getPackageName(), 0); + Preconditions.checkArgument(Binder.getCallingUid() == uid); + } catch (IllegalArgumentException | NullPointerException | + PackageManager.NameNotFoundException e) { + throw new RemoteException(e.getMessage()); + } + } + + private static final class UserState { + @UserIdInt final int mUserId; + final TextClassifierServiceConnection mConnection = new TextClassifierServiceConnection(); + @GuardedBy("mLock") + final Queue mPendingRequests = new ArrayDeque<>(); + @GuardedBy("mLock") + ITextClassifierService mService; + @GuardedBy("mLock") + boolean mBinding; + + private final Context mContext; + private final Object mLock; + + private UserState(int userId, Context context, Object lock) { + mUserId = userId; + mContext = Preconditions.checkNotNull(context); + mLock = Preconditions.checkNotNull(lock); + } + + @GuardedBy("mLock") + boolean isBoundLocked() { + return mService != null; + } + + @GuardedBy("mLock") + private void handlePendingRequestsLocked() { + // TODO(b/72481146): Implement PendingRequest similar to that in RemoteFillService. + PendingRequest request; + while ((request = mPendingRequests.poll()) != null) { + if (isBoundLocked()) { + request.mRequest.run(); + } else { + if (request.mOnServiceFailure != null) { + request.mOnServiceFailure.run(); + } + } + + if (request.mBinder != null) { + request.mBinder.unlinkToDeath(request, 0); + } + } + } + + private boolean bindIfHasPendingRequestsLocked() { + return !mPendingRequests.isEmpty() && bindLocked(); + } + + /** + * @return true if the service is bound or in the process of being bound. + * Returns false otherwise. + */ + private boolean bindLocked() { + if (isBoundLocked() || mBinding) { + return true; + } + + // TODO: Handle bind timeout. + final boolean willBind; + final long identity = Binder.clearCallingIdentity(); + try { + ComponentName componentName = + TextClassifierService.getServiceComponentName(mContext); + if (componentName == null) { + // Might happen if the storage is encrypted and the user is not unlocked + return false; + } + Intent serviceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE) + .setComponent(componentName); + Slog.d(LOG_TAG, "Binding to " + serviceIntent.getComponent()); + willBind = mContext.bindServiceAsUser( + serviceIntent, mConnection, + Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, + UserHandle.of(mUserId)); + mBinding = willBind; + } finally { + Binder.restoreCallingIdentity(identity); + } + return willBind; + } + + private final class TextClassifierServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + init(ITextClassifierService.Stub.asInterface(service)); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + cleanupService(); + } + + @Override + public void onBindingDied(ComponentName name) { + cleanupService(); + } + + @Override + public void onNullBinding(ComponentName name) { + cleanupService(); + } + + void cleanupService() { + init(null); + } + + private void init(@Nullable ITextClassifierService service) { + synchronized (mLock) { + mService = service; + mBinding = false; + handlePendingRequestsLocked(); + } + } + } + } } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index c31cdec0a0fc8b0041759a6531b5ca97e3d393cd..641a1ba686487baa5f210c50db5a6ea77618ecea 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -1096,10 +1096,7 @@ final class AccessibilityController { // Add windows of certain types not covered by modal windows. if (isReportedWindowType(windowState.mAttrs.type)) { // Add the window to the ones to be reported. - WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen); - window.layer = addedWindows.size(); - addedWindows.add(window.token); - windows.add(window); + addPopulatedWindowInfo(windowState, boundsInScreen, windows, addedWindows); if (windowState.isFocused()) { focusedWindowAdded = true; } @@ -1150,10 +1147,8 @@ final class AccessibilityController { computeWindowBoundsInScreen(windowState, boundsInScreen); // Add the window to the ones to be reported. - WindowInfo window = obtainPopulatedWindowInfo(windowState, - boundsInScreen); - addedWindows.add(window.token); - windows.add(window); + addPopulatedWindowInfo( + windowState, boundsInScreen, windows, addedWindows); break; } } @@ -1244,11 +1239,14 @@ final class AccessibilityController { (int) windowFrame.right, (int) windowFrame.bottom); } - private static WindowInfo obtainPopulatedWindowInfo( - WindowState windowState, Rect boundsInScreen) { + private static void addPopulatedWindowInfo( + WindowState windowState, Rect boundsInScreen, + List out, Set tokenOut) { final WindowInfo window = windowState.getWindowInfo(); window.boundsInScreen.set(boundsInScreen); - return window; + window.layer = tokenOut.size(); + out.add(window); + tokenOut.add(window.token); } private void cacheWindows(List windows) { diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java index b00e595db7a1788a4d95ef0fb041b5815a09cf4f..9b787deb8298928ebb3d9c94ef3717ceaf875d3e 100644 --- a/services/core/java/com/android/server/wm/AlertWindowNotification.java +++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java @@ -159,6 +159,7 @@ class AlertWindowNotification { channel.enableVibration(false); channel.setBlockableSystem(true); channel.setGroup(sChannelGroup.getId()); + channel.setBypassDnd(true); mNotificationManager.createNotificationChannel(channel); } diff --git a/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java b/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..ae343da30c740a2bed3d8f1ecba3b142c183e502 --- /dev/null +++ b/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java @@ -0,0 +1,91 @@ +/* + * 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 com.android.server.wm; + +import android.util.ArrayMap; +import android.util.ArraySet; + +import java.util.ArrayList; + +/** + * Keeps track of all {@link AppWindowToken} that are animating and makes sure all animations are + * finished at the same time such that we don't run into issues with z-ordering: An activity A + * that has a shorter animation that is above another activity B with a longer animation in the same + * task, the animation layer would put the B on top of A, but from the hierarchy, A needs to be on + * top of B. Thus, we defer reparenting A to the original hierarchy such that it stays on top of B + * until B finishes animating. + */ +class AnimatingAppWindowTokenRegistry { + + private ArraySet mAnimatingTokens = new ArraySet<>(); + private ArrayMap mFinishedTokens = new ArrayMap<>(); + + private ArrayList mTmpRunnableList = new ArrayList<>(); + + /** + * Notifies that an {@link AppWindowToken} has started animating. + */ + void notifyStarting(AppWindowToken token) { + mAnimatingTokens.add(token); + } + + /** + * Notifies that an {@link AppWindowToken} has finished animating. + */ + void notifyFinished(AppWindowToken token) { + mAnimatingTokens.remove(token); + mFinishedTokens.remove(token); + } + + /** + * Called when an {@link AppWindowToken} is about to finish animating. + * + * @param endDeferFinishCallback Callback to run when defer finish should be ended. + * @return {@code true} if finishing the animation should be deferred, {@code false} otherwise. + */ + boolean notifyAboutToFinish(AppWindowToken token, Runnable endDeferFinishCallback) { + final boolean removed = mAnimatingTokens.remove(token); + if (!removed) { + return false; + } + + if (mAnimatingTokens.isEmpty()) { + + // If no animations are animating anymore, finish all others. + endDeferringFinished(); + return false; + } else { + + // Otherwise let's put it into the pending list of to be finished animations. + mFinishedTokens.put(token, endDeferFinishCallback); + return true; + } + } + + private void endDeferringFinished() { + // Copy it into a separate temp list to avoid modifying the collection while iterating as + // calling the callback may call back into notifyFinished. + for (int i = mFinishedTokens.size() - 1; i >= 0; i--) { + mTmpRunnableList.add(mFinishedTokens.valueAt(i)); + } + mFinishedTokens.clear(); + for (int i = mTmpRunnableList.size() - 1; i >= 0; i--) { + mTmpRunnableList.get(i).run(); + } + mTmpRunnableList.clear(); + } +} diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java index 64f77a2cc4ce71a24d3e88e0b272181893f37d88..00e30507d2328e6ea2d69b3efd32cd1e3f06cc32 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/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index f0ca2ef1747bdafe58ce390d8c335407f4d806aa..93ca4dc48319fa67e1568d77452f9db2a0e71508 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -469,10 +469,16 @@ public class AppTransition implements Dump { * boost the priorities to a more important value whenever an app transition is going to happen * soon or an app transition is running. */ - private void updateBooster() { - WindowManagerService.sThreadPriorityBooster.setAppTransitionRunning( - mNextAppTransition != TRANSIT_UNSET || mAppTransitionState == APP_STATE_READY - || mAppTransitionState == APP_STATE_RUNNING); + void updateBooster() { + WindowManagerService.sThreadPriorityBooster.setAppTransitionRunning(needsBoosting()); + } + + private boolean needsBoosting() { + final boolean recentsAnimRunning = mService.getRecentsAnimationController() != null; + return mNextAppTransition != TRANSIT_UNSET + || mAppTransitionState == APP_STATE_READY + || mAppTransitionState == APP_STATE_RUNNING + || recentsAnimRunning; } void registerListenerLocked(AppTransitionListener listener) { diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index 40f772aaa529e688a7bd9451941ce95aaa18dffa..1575694dc825d283a31d85fb2c7a89d3b6ba564c 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 @@ -615,7 +617,8 @@ public class AppWindowContainerController if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer + " startingWindow=" + mContainer.startingWindow - + " startingView=" + mContainer.startingSurface); + + " startingView=" + mContainer.startingSurface + + " Callers=" + Debug.getCallers(5)); // Use the same thread to remove the window as we used to add it, as otherwise we end up // with things in the view hierarchy being called from different threads. diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 267233750f553d7a5ca6bf042a24ed2666c8c769..f8a454027ec5501a7472272e3e986d9391122195 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -24,7 +24,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.SurfaceControl.HIDDEN; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; @@ -187,6 +186,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; @@ -251,6 +251,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree private final Point mTmpPoint = new Point(); private final Rect mTmpRect = new Rect(); private RemoteAnimationDefinition mRemoteAnimationDefinition; + private AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry; AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, @@ -449,6 +450,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (isReallyAnimating()) { delayed = true; + } else { + + // We aren't animating anything, but exiting windows rely on the animation finished + // callback being called in case the AppWindowToken was pretending to be animating, + // which we might have done because we were in closing/opening apps list. + onAnimationFinished(); } for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) { @@ -705,7 +712,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (destroyedSomething) { final DisplayContent dc = getDisplayContent(); dc.assignWindowLayers(true /*setLayoutNeeded*/); - updateLetterbox(null); + updateLetterboxSurface(null); } } @@ -774,6 +781,16 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree task.mStack.mExitingAppTokens.remove(this); } } + final TaskStack stack = getStack(); + + // If we reparent, make sure to remove ourselves from the old animation registry. + if (mAnimatingAppWindowTokenRegistry != null) { + mAnimatingAppWindowTokenRegistry.notifyFinished(this); + } + mAnimatingAppWindowTokenRegistry = stack != null + ? stack.getAnimatingAppWindowTokenRegistry() + : null; + mLastParent = task; } @@ -972,7 +989,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree void removeChild(WindowState child) { super.removeChild(child); checkKeyguardFlagsChanged(); - updateLetterbox(child); + updateLetterboxSurface(child); } private boolean waitingForReplacement() { @@ -1091,7 +1108,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 +1153,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) { @@ -1444,7 +1480,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return isInterestingAndDrawn; } - void updateLetterbox(WindowState winHint) { + void layoutLetterbox(WindowState winHint) { final WindowState w = findMainWindow(); if (w != winHint && winHint != null && w != null) { return; @@ -1455,19 +1491,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mLetterbox == null) { mLetterbox = new Letterbox(() -> makeChildSurface(null)); } - mLetterbox.setDimensions(mPendingTransaction, getParent().getBounds(), w.mFrame); + mLetterbox.layout(getParent().getBounds(), w.mFrame); } else if (mLetterbox != null) { - final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - // Make sure we have a transaction here, in case we're called outside of a transaction. - // This does not use mPendingTransaction, because SurfaceAnimator uses a - // global transaction in onAnimationEnd. - SurfaceControl.openTransaction(); - try { - mLetterbox.hide(t); - } finally { - SurfaceControl.mergeToGlobalTransaction(t); - SurfaceControl.closeTransaction(); - } + mLetterbox.hide(); + } + } + + void updateLetterboxSurface(WindowState winHint) { + final WindowState w = findMainWindow(); + if (w != winHint && winHint != null && w != null) { + return; + } + layoutLetterbox(winHint); + if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) { + mLetterbox.applySurfaceChanges(mPendingTransaction); } } @@ -1757,6 +1794,21 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return a; } + @Override + public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { + return mAnimatingAppWindowTokenRegistry != null + && mAnimatingAppWindowTokenRegistry.notifyAboutToFinish( + this, endDeferFinishCallback); + } + + @Override + public void onAnimationLeashDestroyed(Transaction t) { + super.onAnimationLeashDestroyed(t); + if (mAnimatingAppWindowTokenRegistry != null) { + mAnimatingAppWindowTokenRegistry.notifyFinished(this); + } + } + @Override protected void setLayer(Transaction t, int layer) { if (!mSurfaceAnimator.hasLeash()) { @@ -1799,6 +1851,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final DisplayContent dc = getDisplayContent(); dc.assignStackOrdering(t); + if (mAnimatingAppWindowTokenRegistry != null) { + mAnimatingAppWindowTokenRegistry.notifyStarting(this); + } } /** @@ -2053,6 +2108,13 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree super.prepareSurfaces(); } + /** + * @return Whether our {@link #getSurfaceControl} is currently showing. + */ + boolean isSurfaceShowing() { + return mLastSurfaceShowing; + } + boolean isFreezingScreen() { return mFreezingScreen; } @@ -2130,4 +2192,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree return new Rect(); } } + + /** + * @eturn true if there is a letterbox and any part of that letterbox overlaps with + * the given {@code rect}. + */ + boolean isLetterboxOverlappingWith(Rect rect) { + return mLetterbox != null && mLetterbox.isOverlappingWith(rect); + } } diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java index f19cd0ff96f70af5550001e7ee769c2c1cc2ca35..1977e126a8a0bb59ef6a4b74c03440bce9bb67ce 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>> 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); @@ -1128,7 +1123,8 @@ class DisplayContent extends WindowContainer= 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=" @@ -235,11 +260,16 @@ public class RecentsAnimationController { return; } try { - final RemoteAnimationTarget[] appAnimations = - new RemoteAnimationTarget[mPendingAnimations.size()]; + final ArrayList 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,11 +278,15 @@ 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); } + final SparseIntArray reasons = new SparseIntArray(); + reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM); + mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING, + reasons).sendToTarget(); } void cancelAnimation() { @@ -279,6 +313,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 +383,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 +397,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 +443,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 169d65e2bdbc229b88260faf9c1d0e7bc39889c2..d645110b6fd5377aeee14f9e9d71bc20fadfe315 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 f32c275b61f14050cb65f74cc4266db00048fa02..32ae52375fd5d241d072d2c87221b14978b2ebb3 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 { 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 mCloseSystemDialogsConsumer = w -> { if (w.mHasSurface) { try { @@ -725,7 +731,7 @@ class RootWindowContainer extends WindowContainer { 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 { // 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 { // 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 5a39de5c3242687371aca356b43958e596e54aa8..235f63e6fd7f5480742df4f4ef321076a3103a83 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -29,6 +29,7 @@ import static com.android.server.wm.proto.ScreenRotationAnimationProto.STARTED; import android.content.Context; import android.graphics.Matrix; import android.graphics.Rect; +import android.os.IBinder; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.Display; @@ -224,8 +225,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 +260,47 @@ 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 + mSurfaceControl = displayContent.makeOverlay() + .setName("ScreenshotSurface") + .setSize(mWidth, mHeight) + .setSecure(isSecure) + .build(); + + // capture a screenshot into the surface we just created + // TODO(multidisplay): we should use the proper display + final int displayId = SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN; + final IBinder displayHandle = SurfaceControl.getBuiltInDisplay(displayId); + // This null check below is to guard a race condition where WMS didn't have a chance to + // respond to display disconnection before handling rotation , that surfaceflinger may + // return a null handle here because it doesn't think that display is valid anymore. + if (displayHandle != null) { 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(); + SurfaceControl.screenshot(displayHandle, 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"); - - setRotationInTransaction(originalRotation); - } finally { - if (!inTransaction) { - mService.closeSurfaceTransaction("ScreenRotationAnimation"); - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, - "<<< CLOSE TRANSACTION ScreenRotationAnimation"); + } else { + Slog.w(TAG, "Built-in display " + displayId + " is null."); } + } 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 +310,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 +348,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 +358,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 +376,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 +535,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 +547,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 +578,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 +604,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 +612,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 +883,7 @@ class ScreenRotationAnimation { return more; } - void updateSurfacesInTransaction() { + void updateSurfaces(SurfaceControl.Transaction t) { if (!mStarted) { return; } @@ -927,28 +891,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 +920,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 76f5396bcb48b918f289a87b738452a7751b0f9d..f10ff8c1dd817a0f7dd2b9e3cc4342a255d400df 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -81,9 +81,14 @@ class SurfaceAnimator { if (anim != mAnimation) { return; } - reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */); - if (animationFinishedCallback != null) { - animationFinishedCallback.run(); + final Runnable resetAndInvokeFinish = () -> { + reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */); + if (animationFinishedCallback != null) { + animationFinishedCallback.run(); + } + }; + if (!mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)) { + resetAndInvokeFinish.run(); } } }; @@ -313,7 +318,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 +329,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"); + } } /** @@ -395,5 +412,17 @@ class SurfaceAnimator { * @return The height of the surface to be animated. */ int getSurfaceHeight(); + + /** + * Gets called when the animation is about to finish and gives the client the opportunity to + * defer finishing the animation, i.e. it keeps the leash around until the client calls + * {@link #cancelAnimation}. + * + * @param endDeferFinishCallback The callback to call when defer finishing should be ended. + * @return Whether the client would like to defer the animation finish. + */ + default boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { + return false; + } } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 2e86351ee4c2d3a7a1ae447bceaf29241b811bba..a403e6f2a212faf38fbc6e2acdbd53049c49b26a 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 { 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 { 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/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index a5a1ca5a9ffe2f250470b73607360339a4833bca..970a8d76a0abe4fa68e0d9e78417b38fcb8da323 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -247,7 +247,8 @@ class TaskSnapshotController { // Ensure at least one window for the top app is visible before attempting to take // a screenshot. Visible here means that the WSA surface is shown and has an alpha // greater than 0. - ws -> ws.mWinAnimator != null && ws.mWinAnimator.getShown() + ws -> (ws.mAppToken == null || ws.mAppToken.isSurfaceShowing()) + && ws.mWinAnimator != null && ws.mWinAnimator.getShown() && ws.mWinAnimator.mLastAlpha > 0f, true); if (!hasVisibleChild) { @@ -273,7 +274,8 @@ class TaskSnapshotController { } return new TaskSnapshot(buffer, top.getConfiguration().orientation, getInsetsFromTaskBounds(mainWindow, task), - isLowRamDevice /* reduced */, scaleFraction /* scale */); + isLowRamDevice /* reduced */, scaleFraction /* scale */, + true /* isRealSnapshot */); } private boolean shouldDisableSnapshots() { @@ -369,7 +371,8 @@ class TaskSnapshotController { } return new TaskSnapshot(hwBitmap.createGraphicBufferHandle(), topChild.getConfiguration().orientation, mainWindow.mStableInsets, - ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */); + ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */, + false /* isRealSnapshot */); } /** diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java index 537f31775951a234c2433e273a3a480db30c66a5..31da5f3ff1c8a77a57c7b82947eac85fff6e4fac 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java @@ -89,7 +89,8 @@ class TaskSnapshotLoader { } return new TaskSnapshot(buffer, proto.orientation, new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom), - reducedResolution, reducedResolution ? REDUCED_SCALE : 1f); + reducedResolution, reducedResolution ? REDUCED_SCALE : 1f, + proto.isRealSnapshot); } catch (IOException e) { Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId); return null; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java index 621bee7d17e0112e48faf80bc4021d635df61207..086fffa9d62146773bcf80191b321c7a3a3f51e5 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java @@ -318,6 +318,7 @@ class TaskSnapshotPersister { proto.insetTop = mSnapshot.getContentInsets().top; proto.insetRight = mSnapshot.getContentInsets().right; proto.insetBottom = mSnapshot.getContentInsets().bottom; + proto.isRealSnapshot = mSnapshot.isRealSnapshot(); final byte[] bytes = TaskSnapshotProto.toByteArray(proto); final File file = getProtoFile(mTaskId, mUserId); final AtomicFile atomicFile = new AtomicFile(file); diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index b5d00a75d7e6fd228ded1ab2344ed3f1ad1b9de6..460edece0f6179d03255c65ec14470df179c0746 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -155,6 +155,9 @@ public class TaskStack extends WindowContainer implements final Rect mTmpDimBoundsRect = new Rect(); private final Point mLastSurfaceSize = new Point(); + private final AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry = + new AnimatingAppWindowTokenRegistry(); + TaskStack(WindowManagerService service, int stackId, StackWindowController controller) { super(service); mStackId = stackId; @@ -1782,4 +1785,8 @@ public class TaskStack extends WindowContainer implements outPos.x -= outset; outPos.y -= outset; } + + AnimatingAppWindowTokenRegistry getAnimatingAppWindowTokenRegistry() { + return mAnimatingAppWindowTokenRegistry; + } } diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java index 43fa3d56914e1e43c27c307bac1e49204342b187..a41eba8205f7a52ebfdd3d5c438bab41b68e88a8 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 ab1019779b0b5555282ce9aa9734585277a7528c..793ffce2466ecfcc3ef88a7563c9a928e35616dc 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 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 5b96bc5c661483e58007720edb16f175298524f4..30064d9765884d5fb3264581ada7f598857a29da 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -25,7 +25,6 @@ import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.StatusBarManager.DISABLE_MASK; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; -import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_USER_HANDLE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; @@ -122,6 +121,7 @@ import android.app.ActivityThread; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.IAssistDataReceiver; +import android.app.admin.DevicePolicyCache; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -387,14 +387,6 @@ public class WindowManagerService extends IWindowManager.Stub case ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED: mKeyguardDisableHandler.sendEmptyMessage(KEYGUARD_POLICY_CHANGED); break; - case ACTION_USER_REMOVED: - final int userId = intent.getIntExtra(EXTRA_USER_HANDLE, USER_NULL); - if (userId != USER_NULL) { - synchronized (mWindowMap) { - mScreenCaptureDisabled.remove(userId); - } - } - break; } } }; @@ -526,13 +518,6 @@ public class WindowManagerService extends IWindowManager.Stub /** List of window currently causing non-system overlay windows to be hidden. */ private ArrayList mHidingNonSystemOverlayWindows = new ArrayList<>(); - /** - * Stores for each user whether screencapture is disabled - * This array is essentially a cache for all userId for - * {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled} - */ - private SparseArray mScreenCaptureDisabled = new SparseArray<>(); - IInputMethodManager mInputMethodManager; AccessibilityController mAccessibilityController; @@ -674,11 +659,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 = @@ -816,6 +808,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(); } @@ -1037,8 +1031,6 @@ public class WindowManagerService extends IWindowManager.Stub IntentFilter filter = new IntentFilter(); // Track changes to DevicePolicyManager state so we can enable/disable keyguard. filter.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); - // Listen to user removal broadcasts so that we can remove the user-specific data. - filter.addAction(Intent.ACTION_USER_REMOVED); mContext.registerReceiver(mBroadcastReceiver, filter); mLatencyTracker = LatencyTracker.getInstance(context); @@ -1134,17 +1126,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new IllegalStateException("Display has not been initialialized"); } - DisplayContent displayContent = mRoot.getDisplayContent(displayId); - - // Adding a window is an exception where the WindowManagerService can create the - // display instead of waiting for the ActivityManagerService to drive creation. - if (displayContent == null) { - final Display display = mDisplayManager.getDisplay(displayId); - - if (display != null) { - displayContent = mRoot.createDisplayContent(display, null /* controller */); - } - } + final DisplayContent displayContent = getDisplayContentOrCreate(displayId); if (displayContent == null) { Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: " @@ -1447,7 +1429,9 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayFrames displayFrames = displayContent.mDisplayFrames; // TODO: Not sure if onDisplayInfoUpdated() call is needed. - displayFrames.onDisplayInfoUpdated(displayContent.getDisplayInfo()); + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); + displayFrames.onDisplayInfoUpdated(displayInfo, + displayContent.calculateDisplayCutoutForRotation(displayInfo.rotation)); final Rect taskBounds; if (atoken != null && atoken.getTask() != null) { taskBounds = mTmpRect; @@ -1494,7 +1478,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; } } @@ -1508,6 +1492,32 @@ public class WindowManagerService extends IWindowManager.Stub return res; } + /** + * Get existing {@link DisplayContent} or create a new one if the display is registered in + * DisplayManager. + * + * NOTE: This should only be used in cases when there is a chance that a {@link DisplayContent} + * that corresponds to a display just added to DisplayManager has not yet been created. This + * usually means that the call of this method was initiated from outside of Activity or Window + * Manager. In most cases the regular getter should be used. + * @see RootWindowContainer#getDisplayContent(int) + */ + private DisplayContent getDisplayContentOrCreate(int displayId) { + DisplayContent displayContent = mRoot.getDisplayContent(displayId); + + // Create an instance if possible instead of waiting for the ActivityManagerService to drive + // the creation. + if (displayContent == null) { + final Display display = mDisplayManager.getDisplay(displayId); + + if (display != null) { + displayContent = mRoot.createDisplayContent(display, null /* controller */); + } + } + + return displayContent; + } + private boolean doesAddToastWindowRequireToken(String packageName, int callingUid, WindowState attachedWindow) { // Try using the target SDK of the root window @@ -1570,41 +1580,32 @@ public class WindowManagerService extends IWindowManager.Stub } } - /** - * Returns whether screen capture is disabled for all windows of a specific user. - */ - boolean isScreenCaptureDisabledLocked(int userId) { - Boolean disabled = mScreenCaptureDisabled.get(userId); - if (disabled == null) { - return false; - } - return disabled; - } - boolean isSecureLocked(WindowState w) { if ((w.mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) { return true; } - if (isScreenCaptureDisabledLocked(UserHandle.getUserId(w.mOwnerUid))) { + if (DevicePolicyCache.getInstance().getScreenCaptureDisabled( + UserHandle.getUserId(w.mOwnerUid))) { return true; } return false; } /** - * Set mScreenCaptureDisabled for specific user + * Set whether screen capture is disabled for all windows of a specific user from + * the device policy cache. */ @Override - public void setScreenCaptureDisabled(int userId, boolean disabled) { + public void refreshScreenCaptureDisabled(int userId) { int callingUid = Binder.getCallingUid(); if (callingUid != SYSTEM_UID) { - throw new SecurityException("Only system can call setScreenCaptureDisabled."); + throw new SecurityException("Only system can call refreshScreenCaptureDisabled."); } synchronized(mWindowMap) { - mScreenCaptureDisabled.put(userId, disabled); // Update secure surface for all windows belonging to this user. - mRoot.setSecureSurfaceState(userId, disabled); + mRoot.setSecureSurfaceState(userId, + DevicePolicyCache.getInstance().getScreenCaptureDisabled(userId)); } } @@ -2056,7 +2057,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) { @@ -2106,7 +2107,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mLastRelayoutContentInsets.set(win.mContentInsets); outVisibleInsets.set(win.mVisibleInsets); outStableInsets.set(win.mStableInsets); - outCutout.set(win.mDisplayCutout); + outCutout.set(win.mDisplayCutout.getDisplayCutout()); outOutsets.set(win.mOutsets); outBackdropFrame.set(win.getBackdropFrame(win.mFrame)); if (localLOGV) Slog.v( @@ -2347,7 +2348,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) { @@ -2374,7 +2375,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); } } @@ -2394,7 +2395,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); @@ -2407,7 +2408,7 @@ public class WindowManagerService extends IWindowManager.Stub if (dc.isDefaultDisplay) { mPolicy.setCurrentOrientationLw(req); } - if (dc.updateRotationUnchecked(inTransaction)) { + if (dc.updateRotationUnchecked()) { // changed return true; } @@ -2675,6 +2676,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mWindowMap) { mRecentsAnimationController = new RecentsAnimationController(this, recentsAnimationRunner, callbacks, displayId); + mAppTransition.updateBooster(); mRecentsAnimationController.initialize(recentTaskIds); } } @@ -2711,6 +2713,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mRecentsAnimationController != null) { mRecentsAnimationController.cleanupAnimation(); mRecentsAnimationController = null; + mAppTransition.updateBooster(); } } } @@ -2880,7 +2883,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 { @@ -3213,6 +3216,12 @@ public class WindowManagerService extends IWindowManager.Stub } } + // Called by window manager policy. Not exposed externally. + @Override + public void switchKeyboardLayout(int deviceId, int direction) { + mInputManager.switchKeyboardLayout(deviceId, direction); + } + // Called by window manager policy. Not exposed externally. @Override public void switchInputMethod(boolean forwardDirection) { @@ -3801,8 +3810,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(); @@ -3827,8 +3835,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(); @@ -5353,8 +5360,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); @@ -5362,7 +5368,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(); } @@ -5678,14 +5684,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; } @@ -5696,8 +5702,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(); @@ -5741,7 +5747,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); @@ -5804,9 +5810,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(); @@ -5829,7 +5836,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 @@ -5843,8 +5850,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) { @@ -5936,6 +5942,16 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public void setShelfHeight(boolean visible, int shelfHeight) { + mAmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR, + "setShelfHeight()"); + synchronized (mWindowMap) { + getDefaultDisplayContentLocked().getPinnedStackController().setAdjustedForShelf(visible, + shelfHeight); + } + } + @Override public void statusBarVisibilityChanged(int visibility) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) @@ -7021,6 +7037,24 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public void dontOverrideDisplayInfo(int displayId) { + synchronized (mWindowMap) { + final DisplayContent dc = getDisplayContentOrCreate(displayId); + if (dc == null) { + throw new IllegalArgumentException( + "Trying to register a non existent display."); + } + // We usually set the override info in DisplayManager so that we get consistent + // values when displays are changing. However, we don't do this for displays that + // serve as containers for ActivityViews because we don't want letter-/pillar-boxing + // during resize. + dc.mShouldOverrideDisplayConfiguration = false; + mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(displayId, + null /* info */); + } + } + @Override public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver) throws RemoteException { @@ -7054,8 +7088,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(); } @@ -7465,5 +7501,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/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index ab139dbb2f12c084d44f2af6b4e376488550c9b5..6e0ccfd5d2db848477e620e8515679ca0b61d391 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -70,8 +70,6 @@ public class WindowManagerShellCommand extends ShellCommand { return runDisplayOverscan(pw); case "scaling": return runDisplayScaling(pw); - case "screen-capture": - return runSetScreenCapture(pw); case "dismiss-keyguard": return runDismissKeyguard(pw); case "tracing": @@ -210,24 +208,6 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } - private int runSetScreenCapture(PrintWriter pw) throws RemoteException { - String userIdStr = getNextArg(); - String enableStr = getNextArg(); - int userId; - boolean disable; - - try { - userId = Integer.parseInt(userIdStr); - } catch (NumberFormatException e) { - getErrPrintWriter().println("Error: bad number " + e); - return -1; - } - - disable = !Boolean.parseBoolean(enableStr); - mInternal.setScreenCaptureDisabled(userId, disable); - return 0; - } - private int runDismissKeyguard(PrintWriter pw) throws RemoteException { mInterface.dismissKeyguard(null /* callback */, null /* message */); return 0; @@ -265,8 +245,6 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" Set overscan area for display."); pw.println(" scaling [off|auto]"); pw.println(" Set display scaling mode."); - pw.println(" screen-capture [userId] [true|false]"); - pw.println(" Enable or disable screen capture."); pw.println(" dismiss-keyguard"); pw.println(" Dismiss the keyguard, prompting user for auth if necessary."); if (!IS_USER) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index c4185fa9a599b858235ff0ca7dcec8f96672f8e6..52e48669834b8bbe6b7b871718f71311d66af722 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -24,7 +24,6 @@ import static android.os.PowerManager.DRAW_WAKE_LOCK; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.SurfaceControl.Transaction; -import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; @@ -35,7 +34,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCRE import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; -import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; @@ -46,7 +44,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FORMAT_CHANGED; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; -import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER; import static android.view.WindowManager.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; @@ -113,6 +110,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; @@ -202,6 +203,7 @@ import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputWindowHandle; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; +import com.android.server.wm.utils.WmDisplayCutout; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -351,8 +353,8 @@ class WindowState extends WindowContainer implements WindowManagerP private boolean mOutsetsChanged = false; /** Part of the display that has been cut away. See {@link DisplayCutout}. */ - DisplayCutout mDisplayCutout = DisplayCutout.NO_CUTOUT; - private DisplayCutout mLastDisplayCutout = DisplayCutout.NO_CUTOUT; + WmDisplayCutout mDisplayCutout = WmDisplayCutout.NO_CUTOUT; + private WmDisplayCutout mLastDisplayCutout = WmDisplayCutout.NO_CUTOUT; private boolean mDisplayCutoutChanged; /** @@ -405,6 +407,9 @@ class WindowState extends WindowContainer implements WindowManagerP private final Rect mParentFrame = new Rect(); + /** Whether the parent frame would have been different if there was no display cutout. */ + private boolean mParentFrameWasClippedByDisplayCutout; + // The entire screen area of the {@link TaskStack} this window is in. Usually equal to the // screen area of the device. final Rect mDisplayFrame = new Rect(); @@ -693,6 +698,7 @@ class WindowState extends WindowContainer implements WindowManagerP mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow; mWindowId = new WindowId(this); mAttrs.copyFrom(a); + mLastSurfaceInsets.set(mAttrs.surfaceInsets); mViewVisibility = viewVisibility; mPolicy = mService.mPolicy; mContext = mService.mContext; @@ -833,7 +839,8 @@ class WindowState extends WindowContainer implements WindowManagerP @Override public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, - Rect outsetFrame, DisplayCutout displayCutout) { + Rect outsetFrame, WmDisplayCutout displayCutout, + boolean parentFrameWasClippedByDisplayCutout) { if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) { // This window is being replaced and either already got information that it's being // removed or we are still waiting for some information. Because of this we don't @@ -842,6 +849,7 @@ class WindowState extends WindowContainer implements WindowManagerP return; } mHaveFrame = true; + mParentFrameWasClippedByDisplayCutout = parentFrameWasClippedByDisplayCutout; final Task task = getTask(); final boolean inFullscreenContainer = inFullscreenContainer(); @@ -1567,7 +1575,9 @@ class WindowState extends WindowContainer 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(); } } @@ -2007,7 +2017,7 @@ class WindowState extends WindowContainer 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*/); @@ -2914,7 +2924,7 @@ class WindowState extends WindowContainer implements WindowManagerP final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING; final boolean reportOrientation = mReportOrientationChanged; final int displayId = getDisplayId(); - final DisplayCutout displayCutout = mDisplayCutout; + final DisplayCutout displayCutout = mDisplayCutout.getDisplayCutout(); if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING && mClient instanceof IWindow.Stub) { // To prevent deadlock simulate one-way call if win.mClient is a local object. @@ -3047,23 +3057,36 @@ class WindowState extends WindowContainer implements WindowManagerP // Only windows with an AppWindowToken are letterboxed. return false; } - if (getDisplayContent().getDisplayInfo().displayCutout == null) { - // No cutout, no letterbox. + if (!mParentFrameWasClippedByDisplayCutout) { + // Cutout didn't make a difference, no letterbox return false; } if (mAttrs.layoutInDisplayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) { // Layout in cutout, no letterbox. return false; } - // TODO: handle dialogs and other non-filling windows - if (mAttrs.layoutInDisplayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) { - // Never layout in cutout, always letterbox. - return true; + if (!mAttrs.isFullscreen()) { + // Not filling the parent frame, no letterbox + return false; } - // Letterbox if any fullscreen mode is set. - final int fl = mAttrs.flags; - final int sysui = mSystemUiVisibility; - return (fl & FLAG_FULLSCREEN) != 0 || (sysui & (SYSTEM_UI_FLAG_FULLSCREEN)) != 0; + // Otherwise we need a letterbox if the layout was smaller than the app window token allowed + // it to be. + return !frameCoversEntireAppTokenBounds(); + } + + /** + * @return true if this window covers the entire bounds of its app window token + * @throws NullPointerException if there is no app window token for this window + */ + private boolean frameCoversEntireAppTokenBounds() { + mTmpRect.set(mAppToken.getBounds()); + mTmpRect.intersectUnchecked(mFrame); + return mAppToken.getBounds().equals(mTmpRect); + } + + @Override + public boolean isLetterboxedOverlappingWith(Rect rect) { + return mAppToken != null && mAppToken.isLetterboxOverlappingWith(rect); } boolean isDragResizeChanged() { @@ -3186,7 +3209,7 @@ class WindowState extends WindowContainer implements WindowManagerP mVisibleInsets.writeToProto(proto, VISIBLE_INSETS); mStableInsets.writeToProto(proto, STABLE_INSETS); mOutsets.writeToProto(proto, OUTSETS); - mDisplayCutout.writeToProto(proto, CUTOUT); + mDisplayCutout.getDisplayCutout().writeToProto(proto, CUTOUT); proto.write(REMOVE_ON_EXIT, mRemoveOnExit); proto.write(DESTROYING, mDestroying); proto.write(REMOVED, mRemoved); @@ -3332,7 +3355,7 @@ class WindowState extends WindowContainer implements WindowManagerP pw.print(" stable="); mStableInsets.printShortString(pw); pw.print(" surface="); mAttrs.surfaceInsets.printShortString(pw); pw.print(" outsets="); mOutsets.printShortString(pw); - pw.print(" cutout=" + mDisplayCutout); + pw.print(" cutout=" + mDisplayCutout.getDisplayCutout()); pw.println(); pw.print(prefix); pw.print("Lst insets: overscan="); mLastOverscanInsets.printShortString(pw); @@ -4289,6 +4312,15 @@ class WindowState extends WindowContainer implements WindowManagerP final boolean wasVisible = isVisibleLw(); result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0; + + if (mWinAnimator.mChildrenDetached) { + // If there are detached children hanging around we need to force + // the client receiving a new Surface. + mWinAnimator.preserveSurfaceLocked(); + result |= RELAYOUT_RES_SURFACE_CHANGED + | RELAYOUT_RES_FIRST_TIME; + } + if (mAnimatingExit) { Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit=" + mRemoveOnExit + ", mDestroying=" + mDestroying); @@ -4493,8 +4525,7 @@ class WindowState extends WindowContainer implements WindowManagerP mAttrs.type == TYPE_NAVIGATION_BAR || // It's tempting to wonder: Have we forgotten the rounded corners overlay? // worry not: it's a fake TYPE_NAVIGATION_BAR_PANEL - mAttrs.type == TYPE_NAVIGATION_BAR_PANEL || - mAttrs.type == TYPE_STATUS_BAR) { + mAttrs.type == TYPE_NAVIGATION_BAR_PANEL) { return false; } return true; @@ -4722,5 +4753,21 @@ class WindowState extends WindowContainer 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 13f05e088cb1e50f22c795e92a1772004bd91b1c..993f8afcb85ff88df0301469a05aafd857c3ef1e 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -221,6 +221,10 @@ class WindowStateAnimator { private final SurfaceControl.Transaction mReparentTransaction = new SurfaceControl.Transaction(); + // Used to track whether we have called detach children on the way to invisibility, in which + // case we need to give the client a new Surface if it lays back out to a visible state. + boolean mChildrenDetached = false; + WindowStateAnimator(final WindowState win) { final WindowManagerService service = win.mService; @@ -430,6 +434,7 @@ class WindowStateAnimator { if (mSurfaceController != null) { return mSurfaceController; } + mChildrenDetached = false; if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) { windowType = SurfaceControl.WINDOW_TYPE_DONT_SCREENSHOT; @@ -507,7 +512,7 @@ class WindowStateAnimator { mDrawState = NO_SURFACE; return null; } catch (Exception e) { - Slog.e(TAG, "Exception creating surface", e); + Slog.e(TAG, "Exception creating surface (parent dead?)", e); mDrawState = NO_SURFACE; return null; } @@ -981,7 +986,7 @@ class WindowStateAnimator { mForceScaleUntilResize = true; } else { if (!w.mSeamlesslyRotated) { - mSurfaceController.setPositionInTransaction(0, 0, recoveringMemory); + mSurfaceController.setPositionInTransaction(mXOffset, mYOffset, recoveringMemory); } } @@ -1415,7 +1420,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 +1462,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 @@ -1479,6 +1483,7 @@ class WindowStateAnimator { if (mSurfaceController != null) { mSurfaceController.detachChildren(); } + mChildrenDetached = true; } int getLayer() { diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index 9d6f8f78c272a6e2b28d6eedd8684e1ae8a9abd1..f6c0a54c74ca0374e9693ae942c8935ecccf5a11 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 417959087de2cff019687c511b6547f1c4fb665f..3256762971fc17aaa1798da1754e7ccebb79ace8 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 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 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 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 collectActivityTypes(ArraySet array1, + ArraySet array2) { + final ArraySet 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 array1, ArraySet array2, Predicate 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; @@ -436,7 +454,7 @@ class WindowSurfacePlacer { AppWindowToken wtoken = mService.mOpeningApps.valueAt(i); if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken); - if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)){ + if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)) { // This token isn't going to be animating. Add it to the list of tokens to // be notified of app transition complete since the notification will not be // sent be the app window animator. @@ -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/core/java/com/android/server/wm/utils/WmDisplayCutout.java b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java new file mode 100644 index 0000000000000000000000000000000000000000..ea3f758fb2091d163e5349897a83da1aabb783d3 --- /dev/null +++ b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java @@ -0,0 +1,173 @@ +/* + * 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 com.android.server.wm.utils; + +import android.graphics.Rect; +import android.util.Size; +import android.view.DisplayCutout; +import android.view.Gravity; + +import java.util.List; +import java.util.Objects; + +/** + * Wrapper for DisplayCutout that also tracks the display size and using this allows (re)calculating + * safe insets. + */ +public class WmDisplayCutout { + + public static final WmDisplayCutout NO_CUTOUT = new WmDisplayCutout(DisplayCutout.NO_CUTOUT, + null); + + private final DisplayCutout mInner; + private final Size mFrameSize; + + public WmDisplayCutout(DisplayCutout inner, Size frameSize) { + mInner = inner; + mFrameSize = frameSize; + } + + public static WmDisplayCutout computeSafeInsets(DisplayCutout inner, + int displayWidth, int displayHeight) { + if (inner == DisplayCutout.NO_CUTOUT || inner.isBoundsEmpty()) { + return NO_CUTOUT; + } + + final Size displaySize = new Size(displayWidth, displayHeight); + final Rect safeInsets = computeSafeInsets(displaySize, inner); + return new WmDisplayCutout(inner.replaceSafeInsets(safeInsets), displaySize); + } + + /** + * Insets the reference frame of the cutout in the given directions. + * + * @return a copy of this instance which has been inset + * @hide + */ + public WmDisplayCutout inset(int insetLeft, int insetTop, int insetRight, int insetBottom) { + DisplayCutout newInner = mInner.inset(insetLeft, insetTop, insetRight, insetBottom); + + if (mInner == newInner) { + return this; + } + + Size frame = mFrameSize == null ? null : new Size( + mFrameSize.getWidth() - insetLeft - insetRight, + mFrameSize.getHeight() - insetTop - insetBottom); + + return new WmDisplayCutout(newInner, frame); + } + + /** + * Recalculates the cutout relative to the given reference frame. + * + * The safe insets must already have been computed, e.g. with {@link #computeSafeInsets}. + * + * @return a copy of this instance with the safe insets recalculated + * @hide + */ + public WmDisplayCutout calculateRelativeTo(Rect frame) { + if (mInner.isEmpty()) { + return this; + } + return inset(frame.left, frame.top, + mFrameSize.getWidth() - frame.right, mFrameSize.getHeight() - frame.bottom); + } + + /** + * Calculates the safe insets relative to the given display size. + * + * @return a copy of this instance with the safe insets calculated + * @hide + */ + public WmDisplayCutout computeSafeInsets(int width, int height) { + return computeSafeInsets(mInner, width, height); + } + + private static Rect computeSafeInsets(Size displaySize, DisplayCutout cutout) { + if (displaySize.getWidth() < displaySize.getHeight()) { + final List boundingRects = cutout.replaceSafeInsets( + new Rect(0, displaySize.getHeight() / 2, 0, displaySize.getHeight() / 2)) + .getBoundingRects(); + int topInset = findInsetForSide(displaySize, boundingRects, Gravity.TOP); + int bottomInset = findInsetForSide(displaySize, boundingRects, Gravity.BOTTOM); + return new Rect(0, topInset, 0, bottomInset); + } else if (displaySize.getWidth() > displaySize.getHeight()) { + final List boundingRects = cutout.replaceSafeInsets( + new Rect(displaySize.getWidth() / 2, 0, displaySize.getWidth() / 2, 0)) + .getBoundingRects(); + int leftInset = findInsetForSide(displaySize, boundingRects, Gravity.LEFT); + int right = findInsetForSide(displaySize, boundingRects, Gravity.RIGHT); + return new Rect(leftInset, 0, right, 0); + } else { + throw new UnsupportedOperationException("not implemented: display=" + displaySize + + " cutout=" + cutout); + } + } + + private static int findInsetForSide(Size display, List boundingRects, int gravity) { + int inset = 0; + final int size = boundingRects.size(); + for (int i = 0; i < size; i++) { + Rect boundingRect = boundingRects.get(i); + switch (gravity) { + case Gravity.TOP: + if (boundingRect.top == 0) { + inset = Math.max(inset, boundingRect.bottom); + } + break; + case Gravity.BOTTOM: + if (boundingRect.bottom == display.getHeight()) { + inset = Math.max(inset, display.getHeight() - boundingRect.top); + } + break; + case Gravity.LEFT: + if (boundingRect.left == 0) { + inset = Math.max(inset, boundingRect.right); + } + break; + case Gravity.RIGHT: + if (boundingRect.right == display.getWidth()) { + inset = Math.max(inset, display.getWidth() - boundingRect.left); + } + break; + default: + throw new IllegalArgumentException("unknown gravity: " + gravity); + } + } + return inset; + } + + public DisplayCutout getDisplayCutout() { + return mInner; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof WmDisplayCutout)) { + return false; + } + WmDisplayCutout that = (WmDisplayCutout) o; + return Objects.equals(mInner, that.mInner) && + Objects.equals(mFrameSize, that.mFrameSize); + } + + @Override + public int hashCode() { + return Objects.hash(mInner, mFrameSize); + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..37b5ad1eb61063403541264efab42d10f00d3b38 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java @@ -0,0 +1,57 @@ +/* + * 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 com.android.server.devicepolicy; + +import android.app.admin.DevicePolicyCache; +import android.util.SparseBooleanArray; + +import com.android.internal.annotations.GuardedBy; + +/** + * Implementation of {@link DevicePolicyCache}, to which {@link DevicePolicyManagerService} pushes + * policies. + * + * TODO Move other copies of policies into this class too. + */ +public class DevicePolicyCacheImpl extends DevicePolicyCache { + /** + * Lock object. For simplicity we just always use this as the lock. We could use each object + * as a lock object to make it more fine-grained, but that'd make copy-paste error-prone. + */ + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private final SparseBooleanArray mScreenCaptureDisabled = new SparseBooleanArray(); + + public void onUserRemoved(int userHandle) { + synchronized (mLock) { + mScreenCaptureDisabled.delete(userHandle); + } + } + + @Override + public boolean getScreenCaptureDisabled(int userHandle) { + synchronized (mLock) { + return mScreenCaptureDisabled.get(userHandle); + } + } + + public void setScreenCaptureDisabled(int userHandle, boolean disabled) { + synchronized (mLock) { + mScreenCaptureDisabled.put(userHandle, disabled); + } + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index ab8a6c4d754a3b41db8d9de13299469705f5b465..6a9b862743f9e81947dd4f61f90d2d0684998045 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -98,6 +98,7 @@ import android.app.PendingIntent; import android.app.StatusBarManager; import android.app.admin.DeviceAdminInfo; import android.app.admin.DeviceAdminReceiver; +import android.app.admin.DevicePolicyCache; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.NetworkEvent; @@ -436,6 +437,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private final DeviceAdminServiceController mDeviceAdminServiceController; private final OverlayPackagesProvider mOverlayPackagesProvider; + private final DevicePolicyCacheImpl mPolicyCache = new DevicePolicyCacheImpl(); + /** * Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p * is requested for user u. @@ -563,7 +566,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @NonNull PasswordMetrics mActivePasswordMetrics = new PasswordMetrics(); int mFailedPasswordAttempts = 0; boolean mPasswordStateHasBeenSetSinceBoot = false; - boolean mPasswordValidAtLastCheckpoint = false; + boolean mPasswordValidAtLastCheckpoint = true; int mUserHandle; int mPasswordOwner = -1; @@ -2176,6 +2179,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring."); return; } + mPolicyCache.onUserRemoved(userHandle); + mOwners.removeProfileOwner(userHandle); mOwners.writeProfileOwner(userHandle); @@ -2188,7 +2193,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { policyFile.delete(); Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath()); } - updateScreenCaptureDisabledInWindowManager(userHandle, false /* default value */); } void loadOwners() { @@ -3395,7 +3399,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override void handleStartUser(int userId) { - updateScreenCaptureDisabledInWindowManager(userId, + updateScreenCaptureDisabled(userId, getScreenCaptureDisabled(null, userId)); pushUserRestrictions(userId); @@ -3883,23 +3887,28 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final PasswordMetrics metrics = ap.minimumPasswordMetrics; if (metrics.quality != quality) { metrics.quality = quality; - updatePasswordValidityCheckpointLocked(userId); - saveSettingsLocked(userId); + updatePasswordValidityCheckpointLocked(userId, parent); } maybeLogPasswordComplexitySet(who, userId, parent, metrics); } } /** - * Updates flag in memory that tells us whether the user's password currently satisfies the - * requirements set by all of the user's active admins. This should be called before - * {@link #saveSettingsLocked} whenever the password or the admin policies have changed. + * Updates a flag that tells us whether the user's password currently satisfies the + * requirements set by all of the user's active admins. The flag is updated both in memory + * and persisted to disk by calling {@link #saveSettingsLocked}, for the value of the flag + * be the correct one upon boot. + * This should be called whenever the password or the admin policies have changed. */ @GuardedBy("DevicePolicyManagerService.this") - private void updatePasswordValidityCheckpointLocked(int userHandle) { - DevicePolicyData policy = getUserData(userHandle); - policy.mPasswordValidAtLastCheckpoint = isActivePasswordSufficientForUserLocked( - policy, policy.mUserHandle, false); + private void updatePasswordValidityCheckpointLocked(int userHandle, boolean parent) { + final int credentialOwner = getCredentialOwner(userHandle, parent); + DevicePolicyData policy = getUserData(credentialOwner); + policy.mPasswordValidAtLastCheckpoint = + isPasswordSufficientForUserWithoutCheckpointLocked( + policy.mActivePasswordMetrics, userHandle, parent); + + saveSettingsLocked(credentialOwner); } @Override @@ -3986,8 +3995,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final PasswordMetrics metrics = ap.minimumPasswordMetrics; if (metrics.length != length) { metrics.length = length; - updatePasswordValidityCheckpointLocked(userId); - saveSettingsLocked(userId); + updatePasswordValidityCheckpointLocked(userId, parent); } maybeLogPasswordComplexitySet(who, userId, parent, metrics); } @@ -4011,8 +4019,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); if (ap.passwordHistoryLength != length) { ap.passwordHistoryLength = length; - updatePasswordValidityCheckpointLocked(userId); - saveSettingsLocked(userId); + updatePasswordValidityCheckpointLocked(userId, parent); } } if (SecurityLog.isLoggingEnabled()) { @@ -4213,8 +4220,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final PasswordMetrics metrics = ap.minimumPasswordMetrics; if (metrics.upperCase != length) { metrics.upperCase = length; - updatePasswordValidityCheckpointLocked(userId); - saveSettingsLocked(userId); + updatePasswordValidityCheckpointLocked(userId, parent); } maybeLogPasswordComplexitySet(who, userId, parent, metrics); } @@ -4236,8 +4242,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final PasswordMetrics metrics = ap.minimumPasswordMetrics; if (metrics.lowerCase != length) { metrics.lowerCase = length; - updatePasswordValidityCheckpointLocked(userId); - saveSettingsLocked(userId); + updatePasswordValidityCheckpointLocked(userId, parent); } maybeLogPasswordComplexitySet(who, userId, parent, metrics); } @@ -4262,8 +4267,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final PasswordMetrics metrics = ap.minimumPasswordMetrics; if (metrics.letters != length) { metrics.letters = length; - updatePasswordValidityCheckpointLocked(userId); - saveSettingsLocked(userId); + updatePasswordValidityCheckpointLocked(userId, parent); } maybeLogPasswordComplexitySet(who, userId, parent, metrics); } @@ -4288,8 +4292,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final PasswordMetrics metrics = ap.minimumPasswordMetrics; if (metrics.numeric != length) { metrics.numeric = length; - updatePasswordValidityCheckpointLocked(userId); - saveSettingsLocked(userId); + updatePasswordValidityCheckpointLocked(userId, parent); } maybeLogPasswordComplexitySet(who, userId, parent, metrics); } @@ -4314,8 +4317,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final PasswordMetrics metrics = ap.minimumPasswordMetrics; if (metrics.symbols != length) { ap.minimumPasswordMetrics.symbols = length; - updatePasswordValidityCheckpointLocked(userId); - saveSettingsLocked(userId); + updatePasswordValidityCheckpointLocked(userId, parent); } maybeLogPasswordComplexitySet(who, userId, parent, metrics); } @@ -4340,8 +4342,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final PasswordMetrics metrics = ap.minimumPasswordMetrics; if (metrics.nonLetter != length) { ap.minimumPasswordMetrics.nonLetter = length; - updatePasswordValidityCheckpointLocked(userId); - saveSettingsLocked(userId); + updatePasswordValidityCheckpointLocked(userId, parent); } maybeLogPasswordComplexitySet(who, userId, parent, metrics); } @@ -4562,16 +4563,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private boolean isActivePasswordSufficientForUserLocked( DevicePolicyData policy, int userHandle, boolean parent) { - final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent); - if (requiredPasswordQuality == PASSWORD_QUALITY_UNSPECIFIED) { - // A special case is when there is no required password quality, then we just return - // true since any password would be sufficient. This is for the scenario when a work - // profile is first created so there is no information about the current password but - // it should be considered sufficient as there is no password requirement either. - // This is useful since it short-circuits the password checkpoint for FDE device below. - return true; - } - if (!mInjector.storageManagerIsFileBasedEncryptionEnabled() && !policy.mPasswordStateHasBeenSetSinceBoot) { // Before user enters their password for the first time after a reboot, return the @@ -4582,28 +4573,41 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return policy.mPasswordValidAtLastCheckpoint; } - if (policy.mActivePasswordMetrics.quality < requiredPasswordQuality) { + return isPasswordSufficientForUserWithoutCheckpointLocked( + policy.mActivePasswordMetrics, userHandle, parent); + } + + /** + * Returns {@code true} if the password represented by the {@code passwordMetrics} argument + * sufficiently fulfills the password requirements for the user corresponding to + * {@code userHandle} (or its parent, if {@code parent} is set to {@code true}). + */ + private boolean isPasswordSufficientForUserWithoutCheckpointLocked( + PasswordMetrics passwordMetrics, int userHandle, boolean parent) { + final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent); + + if (passwordMetrics.quality < requiredPasswordQuality) { return false; } if (requiredPasswordQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC - && policy.mActivePasswordMetrics.length < getPasswordMinimumLength( + && passwordMetrics.length < getPasswordMinimumLength( null, userHandle, parent)) { return false; } if (requiredPasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { return true; } - return policy.mActivePasswordMetrics.upperCase >= getPasswordMinimumUpperCase( + return passwordMetrics.upperCase >= getPasswordMinimumUpperCase( null, userHandle, parent) - && policy.mActivePasswordMetrics.lowerCase >= getPasswordMinimumLowerCase( + && passwordMetrics.lowerCase >= getPasswordMinimumLowerCase( null, userHandle, parent) - && policy.mActivePasswordMetrics.letters >= getPasswordMinimumLetters( + && passwordMetrics.letters >= getPasswordMinimumLetters( null, userHandle, parent) - && policy.mActivePasswordMetrics.numeric >= getPasswordMinimumNumeric( + && passwordMetrics.numeric >= getPasswordMinimumNumeric( null, userHandle, parent) - && policy.mActivePasswordMetrics.symbols >= getPasswordMinimumSymbols( + && passwordMetrics.symbols >= getPasswordMinimumSymbols( null, userHandle, parent) - && policy.mActivePasswordMetrics.nonLetter >= getPasswordMinimumNonLetter( + && passwordMetrics.nonLetter >= getPasswordMinimumNonLetter( null, userHandle, parent); } @@ -6144,8 +6148,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try { synchronized (this) { policy.mFailedPasswordAttempts = 0; - updatePasswordValidityCheckpointLocked(userId); - saveSettingsLocked(userId); + updatePasswordValidityCheckpointLocked(userId, /* parent */ false); updatePasswordExpirationsLocked(userId); setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false); @@ -6462,8 +6465,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } /** - * Set the storage encryption request for a single admin. Returns the new total request - * status (for all admins). + * Called by an application that is administering the device to request that the storage system + * be encrypted. Does nothing if the caller is on a secondary user or a managed profile. + * + * @return the new total request status (for all admins), or {@link + * DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} if called for a non-system user */ @Override public int setStorageEncryption(ComponentName who, boolean encrypt) { @@ -6478,7 +6484,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (userHandle != UserHandle.USER_SYSTEM) { Slog.w(LOG_TAG, "Only owner/system user is allowed to set storage encryption. User " + UserHandle.getCallingUserId() + " is not permitted."); - return 0; + return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED; } ActiveAdmin ap = getActiveAdminForCallerLocked(who, @@ -6632,7 +6638,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (ap.disableScreenCapture != disabled) { ap.disableScreenCapture = disabled; saveSettingsLocked(userHandle); - updateScreenCaptureDisabledInWindowManager(userHandle, disabled); + updateScreenCaptureDisabled(userHandle, disabled); } } } @@ -6664,13 +6670,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private void updateScreenCaptureDisabledInWindowManager(final int userHandle, - final boolean disabled) { + private void updateScreenCaptureDisabled(int userHandle, boolean disabled) { + mPolicyCache.setScreenCaptureDisabled(userHandle, disabled); mHandler.post(new Runnable() { @Override public void run() { try { - mInjector.getIWindowManager().setScreenCaptureDisabled(userHandle, disabled); + mInjector.getIWindowManager().refreshScreenCaptureDisabled(userHandle); } catch (RemoteException e) { Log.w(LOG_TAG, "Unable to notify WindowManager.", e); } @@ -10502,6 +10508,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .getResources().getString(R.string.printing_disabled_by, appLabel); } } + + @Override + protected DevicePolicyCache getDevicePolicyCache() { + return mPolicyCache; + } } private Intent createShowAdminSupportIntent(ComponentName admin, int userId) { @@ -12658,8 +12669,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final DeviceAdminInfo incomingDeviceInfo = findAdmin(target, callingUserId, /* throwForMissingPermission= */ true); checkActiveAdminPrecondition(target, incomingDeviceInfo, policy); - if (!incomingDeviceInfo.getActivityInfo().metaData - .getBoolean(DeviceAdminReceiver.SUPPORT_TRANSFER_OWNERSHIP_META_DATA, false)) { + if (!incomingDeviceInfo.supportsTransferOwnership()) { throw new IllegalArgumentException("Provided target does not support " + "ownership transfer."); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b7936e5215f7ecea73d64134e21ce9c93749946a..cb46e4fefb786f7ec019ddafd6e716b7a640c323 100755 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -202,6 +202,8 @@ public final class SystemServer { "com.android.server.search.SearchManagerService$Lifecycle"; private static final String THERMAL_OBSERVER_CLASS = "com.google.android.clockwork.ThermalObserver"; + private static final String WEAR_CONFIG_SERVICE_CLASS = + "com.google.android.clockwork.WearConfigManagerService"; private static final String WEAR_CONNECTIVITY_SERVICE_CLASS = "com.android.clockwork.connectivity.WearConnectivityService"; private static final String WEAR_SIDEKICK_SERVICE_CLASS = @@ -698,11 +700,6 @@ public final class SystemServer { * Starts some essential services that are not tangled up in the bootstrap process. */ private void startCoreServices() { - // Records errors and logs, for example wtf() - traceBeginAndSlog("StartDropBoxManager"); - mSystemServiceManager.startService(DropBoxManagerService.class); - traceEnd(); - traceBeginAndSlog("StartBatteryService"); // Tracks the battery level. Requires LightService. mSystemServiceManager.startService(BatteryService.class); @@ -832,6 +829,13 @@ public final class SystemServer { SQLiteCompatibilityWalFlags.reset(); traceEnd(); + // Records errors and logs, for example wtf() + // Currently this service indirectly depends on SettingsProvider so do this after + // InstallSystemProviders. + traceBeginAndSlog("StartDropBoxManager"); + mSystemServiceManager.startService(DropBoxManagerService.class); + traceEnd(); + traceBeginAndSlog("StartVibratorService"); vibrator = new VibratorService(context); ServiceManager.addService("vibrator", vibrator); @@ -1584,6 +1588,10 @@ public final class SystemServer { } if (isWatch) { + traceBeginAndSlog("StartWearConfigService"); + mSystemServiceManager.startService(WEAR_CONFIG_SERVICE_CLASS); + traceEnd(); + traceBeginAndSlog("StartWearConnectivityService"); mSystemServiceManager.startService(WEAR_CONNECTIVITY_SERVICE_CLASS); traceEnd(); diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk index aed57e3b6dccde9230695a044dd89b385d0f380d..3d7fdbdd7436099d00220ae0f88502dcc5efa24d 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/BackupAgentTimeoutParametersTest.java b/services/robotests/src/com/android/server/backup/BackupAgentTimeoutParametersTest.java new file mode 100644 index 0000000000000000000000000000000000000000..801451ee549b9849bf3e70e952117436be75bda0 --- /dev/null +++ b/services/robotests/src/com/android/server/backup/BackupAgentTimeoutParametersTest.java @@ -0,0 +1,140 @@ +/* + * 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 com.android.server.backup; + +import static org.junit.Assert.assertEquals; + +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.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +/** Tests for {@link BackupAgentTimeoutParameters}. */ +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderPackages({"com.android.server.backup"}) +@SystemLoaderClasses({KeyValueSettingObserver.class}) +@Presubmit +public class BackupAgentTimeoutParametersTest { + private ContentResolver mContentResolver; + private BackupAgentTimeoutParameters mParameters; + + /** Initialize timeout parameters and start observing changes. */ + @Before + public void setUp() { + Context context = RuntimeEnvironment.application.getApplicationContext(); + + mContentResolver = context.getContentResolver(); + mParameters = new BackupAgentTimeoutParameters(new Handler(), mContentResolver); + mParameters.start(); + } + + /** Stop observing changes to the setting. */ + @After + public void tearDown() { + mParameters.stop(); + } + + /** Tests that timeout parameters are initialized with default values on creation. */ + @Test + public void testGetParameters_afterConstructorWithStart_returnsDefaultValues() { + long kvBackupAgentTimeoutMillis = mParameters.getKvBackupAgentTimeoutMillis(); + long fullBackupAgentTimeoutMillis = mParameters.getFullBackupAgentTimeoutMillis(); + long sharedBackupAgentTimeoutMillis = mParameters.getSharedBackupAgentTimeoutMillis(); + long restoreAgentTimeoutMillis = mParameters.getRestoreAgentTimeoutMillis(); + long restoreAgentFinishedTimeoutMillis = mParameters.getRestoreAgentFinishedTimeoutMillis(); + + assertEquals( + BackupAgentTimeoutParameters.DEFAULT_KV_BACKUP_AGENT_TIMEOUT_MILLIS, + kvBackupAgentTimeoutMillis); + assertEquals( + BackupAgentTimeoutParameters.DEFAULT_FULL_BACKUP_AGENT_TIMEOUT_MILLIS, + fullBackupAgentTimeoutMillis); + assertEquals( + BackupAgentTimeoutParameters.DEFAULT_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS, + sharedBackupAgentTimeoutMillis); + assertEquals( + BackupAgentTimeoutParameters.DEFAULT_RESTORE_AGENT_TIMEOUT_MILLIS, + restoreAgentTimeoutMillis); + assertEquals( + BackupAgentTimeoutParameters.DEFAULT_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS, + restoreAgentFinishedTimeoutMillis); + } + + /** + * Tests that timeout parameters are updated when we call start, even when a setting change + * occurs while we are not observing. + */ + @Test + public void testGetParameters_withSettingChangeBeforeStart_updatesValues() { + mParameters.stop(); + long testTimeout = BackupAgentTimeoutParameters.DEFAULT_KV_BACKUP_AGENT_TIMEOUT_MILLIS * 2; + final String setting = + BackupAgentTimeoutParameters.SETTING_KV_BACKUP_AGENT_TIMEOUT_MILLIS + + "=" + + testTimeout; + putStringAndNotify(setting); + mParameters.start(); + + long kvBackupAgentTimeoutMillis = mParameters.getKvBackupAgentTimeoutMillis(); + + assertEquals(testTimeout, kvBackupAgentTimeoutMillis); + } + + /** + * Tests that timeout parameters are updated when a setting change occurs while we are observing + * changes. + */ + @Test + public void testGetParameters_withSettingChangeAfterStart_updatesValues() { + long testTimeout = BackupAgentTimeoutParameters.DEFAULT_KV_BACKUP_AGENT_TIMEOUT_MILLIS * 2; + final String setting = + BackupAgentTimeoutParameters.SETTING_KV_BACKUP_AGENT_TIMEOUT_MILLIS + + "=" + + testTimeout; + putStringAndNotify(setting); + + long kvBackupAgentTimeoutMillis = mParameters.getKvBackupAgentTimeoutMillis(); + + assertEquals(testTimeout, kvBackupAgentTimeoutMillis); + } + + /** + * 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.Global.putString(mContentResolver, BackupAgentTimeoutParameters.SETTING, 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.Global.getUriFor(BackupAgentTimeoutParameters.SETTING), /*observer*/ null); + } +} diff --git a/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java b/services/robotests/src/com/android/server/backup/BackupManagerConstantsTest.java index 0752537abfccf67209605e838ae7ce6d7b98981b..2a32c2eef6ca7649059782839079dd99f6e973c7 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/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java index 3d2d8afd4a354b1330dcb687e59e94ad26192756..bbec7af34d71b8b7f21f9cd7aea1777f77f6ad43 100644 --- a/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java +++ b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java @@ -60,7 +60,7 @@ public class TransportClientManagerTest { public void setUp() { MockitoAnnotations.initMocks(this); - mTransportClientManager = new TransportClientManager(mContext); + mTransportClientManager = new TransportClientManager(mContext, new TransportStats()); mTransportComponent = new ComponentName(PACKAGE_NAME, CLASS_NAME); mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent); diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java index 5b65473e07837ede0ed8fd450fdcdf3a0598317f..49ef581f03b517a7e665fbd5c2c2853823b83b38 100644 --- a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java +++ b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java @@ -88,6 +88,7 @@ public class TransportClientTest { @Mock private TransportConnectionListener mTransportConnectionListener; @Mock private TransportConnectionListener mTransportConnectionListener2; @Mock private IBackupTransport.Stub mTransportBinder; + private TransportStats mTransportStats; private TransportClient mTransportClient; private ComponentName mTransportComponent; private String mTransportString; @@ -105,10 +106,12 @@ public class TransportClientTest { mTransportComponent = new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport"); mTransportString = mTransportComponent.flattenToShortString(); + mTransportStats = new TransportStats(); mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent); mTransportClient = new TransportClient( mContext, + mTransportStats, mBindIntent, mTransportComponent, "1", diff --git a/services/robotests/src/com/android/server/backup/transport/TransportStatsTest.java b/services/robotests/src/com/android/server/backup/transport/TransportStatsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..322db85c4f42fa69c5f21ed9fe0dd46192d5078a --- /dev/null +++ b/services/robotests/src/com/android/server/backup/transport/TransportStatsTest.java @@ -0,0 +1,105 @@ +/* + * 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 com.android.server.backup.transport; + +import static com.android.server.backup.testing.TransportData.backupTransport; +import static com.android.server.backup.testing.TransportData.d2dTransport; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.ComponentName; +import android.platform.test.annotations.Presubmit; + +import com.android.server.backup.transport.TransportStats.Stats; +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderPackages({"com.android.server.backup"}) +@Presubmit +public class TransportStatsTest { + private static final double TOLERANCE = 0.0001; + + private TransportStats mTransportStats; + private ComponentName mTransportComponent1; + private ComponentName mTransportComponent2; + + @Before + public void setUp() throws Exception { + mTransportStats = new TransportStats(); + mTransportComponent1 = backupTransport().getTransportComponent(); + mTransportComponent2 = d2dTransport().getTransportComponent(); + } + + @Test + public void testRegisterConnectionTime() { + mTransportStats.registerConnectionTime(mTransportComponent1, 50L); + + Stats stats = mTransportStats.getStatsForTransport(mTransportComponent1); + assertThat(stats.average).isWithin(TOLERANCE).of(50); + assertThat(stats.max).isEqualTo(50L); + assertThat(stats.min).isEqualTo(50L); + assertThat(stats.n).isEqualTo(1); + } + + @Test + public void testRegisterConnectionTime_whenHasAlreadyOneSample() { + mTransportStats.registerConnectionTime(mTransportComponent1, 50L); + + mTransportStats.registerConnectionTime(mTransportComponent1, 100L); + + Stats stats = mTransportStats.getStatsForTransport(mTransportComponent1); + assertThat(stats.average).isWithin(TOLERANCE).of(75); + assertThat(stats.max).isEqualTo(100L); + assertThat(stats.min).isEqualTo(50L); + assertThat(stats.n).isEqualTo(2); + } + + @Test + public void testGetStatsForTransport() { + mTransportStats.registerConnectionTime(mTransportComponent1, 10L); + mTransportStats.registerConnectionTime(mTransportComponent2, 20L); + + Stats stats = mTransportStats.getStatsForTransport(mTransportComponent1); + + assertThat(stats.average).isWithin(TOLERANCE).of(10); + assertThat(stats.max).isEqualTo(10L); + assertThat(stats.min).isEqualTo(10L); + assertThat(stats.n).isEqualTo(1); + } + + @Test + public void testMerge() { + mTransportStats.registerConnectionTime(mTransportComponent1, 10L); + mTransportStats.registerConnectionTime(mTransportComponent2, 20L); + Stats stats1 = mTransportStats.getStatsForTransport(mTransportComponent1); + Stats stats2 = mTransportStats.getStatsForTransport(mTransportComponent2); + + Stats stats = Stats.merge(stats1, stats2); + + assertThat(stats.average).isWithin(TOLERANCE).of(15); + assertThat(stats.max).isEqualTo(20L); + assertThat(stats.min).isEqualTo(10L); + assertThat(stats.n).isEqualTo(2); + } +} diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index 356e64b5dd7bd4156f367cf30aa24c3b7d14e344..0ca0a1a104c8f6556ba800b391f457853728940e 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -15,6 +15,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ frameworks-base-testutils \ services.accessibility \ services.appwidget \ + services.autofill \ services.backup \ services.core \ services.devicepolicy \ diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java index 0462b143049615ddcc26e26fc15a350fd7a51b6d..e5c6c6e51430d337adfd7c86ca06b3fceeb91dda 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java @@ -16,6 +16,9 @@ package com.android.server.accessibility; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -57,6 +60,7 @@ public class AccessibilityServiceConnectionTest { static final int SERVICE_ID = 42; AccessibilityServiceConnection mConnection; + @Mock AccessibilityManagerService.UserState mMockUserState; @Mock Context mMockContext; @Mock AccessibilityServiceInfo mMockServiceInfo; @@ -66,7 +70,9 @@ public class AccessibilityServiceConnectionTest { @Mock WindowManagerInternal mMockWindowManagerInternal; @Mock GlobalActionPerformer mMockGlobalActionPerformer; @Mock KeyEventDispatcher mMockKeyEventDispatcher; + @Mock MagnificationController mMockMagnificationController; + MessageCapturingHandler mHandler = new MessageCapturingHandler(null); @BeforeClass public static void oneTimeInitialization() { @@ -79,12 +85,15 @@ public class AccessibilityServiceConnectionTest { public void setup() { MockitoAnnotations.initMocks(this); when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mMockKeyEventDispatcher); + when(mMockSystemSupport.getMagnificationController()) + .thenReturn(mMockMagnificationController); + when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo); mMockResolveInfo.serviceInfo = mock(ServiceInfo.class); mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class); mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext, - COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, new Handler(), new Object(), + COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(), mMockSecurityPolicy, mMockSystemSupport, mMockWindowManagerInternal, mMockGlobalActionPerformer); } @@ -106,12 +115,30 @@ public class AccessibilityServiceConnectionTest { @Test public void bindConnectUnbind_linksAndUnlinksToServiceDeath() throws RemoteException { IBinder mockBinder = mock(IBinder.class); - when(mMockUserState.getBindingServicesLocked()) - .thenReturn(new HashSet<>(Arrays.asList(COMPONENT_NAME))); + setServiceBinding(COMPONENT_NAME); mConnection.bindLocked(); mConnection.onServiceConnected(COMPONENT_NAME, mockBinder); verify(mockBinder).linkToDeath(eq(mConnection), anyInt()); mConnection.unbindLocked(); verify(mockBinder).unlinkToDeath(eq(mConnection), anyInt()); } + + @Test + public void connectedServiceCrashedAndRestarted_crashReportedInServiceInfo() { + IBinder mockBinder = mock(IBinder.class); + setServiceBinding(COMPONENT_NAME); + mConnection.bindLocked(); + mConnection.onServiceConnected(COMPONENT_NAME, mockBinder); + assertFalse(mConnection.getServiceInfo().crashed); + mConnection.binderDied(); + assertTrue(mConnection.getServiceInfo().crashed); + mConnection.onServiceConnected(COMPONENT_NAME, mockBinder); + mHandler.sendAllMessages(); + assertFalse(mConnection.getServiceInfo().crashed); + } + + private void setServiceBinding(ComponentName componentName) { + when(mMockUserState.getBindingServicesLocked()) + .thenReturn(new HashSet<>(Arrays.asList(componentName))); + } } 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 5b1f5c176f5772fbbf2ae23b41e8abc802a48ba1..1ba1788ed55a17ed23885a292be58a44c296f808 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java @@ -34,6 +34,8 @@ import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT; +import static junit.framework.TestCase.assertNotNull; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -45,6 +47,8 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; + +import android.app.ActivityOptions; import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.PauseActivityItem; import android.graphics.Rect; @@ -123,12 +127,20 @@ public class ActivityRecordTests extends ActivityTestsBase { } return null; }).when(mActivity.app.thread).scheduleTransaction(any()); + mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped"); + // The activity is in the focused stack so it should not move to paused. mActivity.makeVisibleIfNeeded(null /* starting */); + assertTrue(mActivity.isState(STOPPED)); + assertFalse(pauseFound.value); - assertTrue(mActivity.isState(PAUSING)); + // Clear focused stack + mActivity.mStackSupervisor.mFocusedStack = null; + // In the unfocused stack, the activity should move to paused. + mActivity.makeVisibleIfNeeded(null /* starting */); + assertTrue(mActivity.isState(PAUSING)); assertTrue(pauseFound.value); // Make sure that the state does not change for current non-stopping states. @@ -193,6 +205,35 @@ public class ActivityRecordTests extends ActivityTestsBase { false /*activityResizeable*/, true /*expected*/); } + @Test + public void testsApplyOptionsLocked() { + ActivityOptions activityOptions = ActivityOptions.makeBasic(); + + // Set and apply options for ActivityRecord. Pending options should be cleared + mActivity.updateOptionsLocked(activityOptions); + mActivity.applyOptionsLocked(); + assertNull(mActivity.pendingOptions); + + // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options. + // Pending options should be cleared for both ActivityRecords + ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build(); + activity2.updateOptionsLocked(activityOptions); + mActivity.updateOptionsLocked(activityOptions); + mActivity.applyOptionsLocked(); + assertNull(mActivity.pendingOptions); + assertNull(activity2.pendingOptions); + + // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options. + // Pending options should be cleared for only ActivityRecord that was applied + TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build(); + activity2 = new ActivityBuilder(mService).setTask(task2).build(); + activity2.updateOptionsLocked(activityOptions); + mActivity.updateOptionsLocked(activityOptions); + mActivity.applyOptionsLocked(); + assertNull(mActivity.pendingOptions); + assertNotNull(activity2.pendingOptions); + } + private void testSupportsLaunchingResizeable(boolean taskPresent, boolean taskResizeable, boolean activityResizeable, boolean expected) { mService.mSupportsMultiWindow = true; @@ -214,35 +255,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 bda68d16320f6c031ae65bef6e41a7ffc8d08bd5..08158ec9c84465a1733c4fc986b2dcf69a81cc8d 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -37,12 +37,15 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.servertransaction.DestroyActivityItem; import android.content.pm.ActivityInfo; +import android.os.Debug; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; @@ -94,24 +97,6 @@ public class ActivityStackTests extends ActivityTestsBase { assertNotNull(mTask.getWindowContainerController()); } - @Test - public void testNoPauseDuringResumeTopActivity() throws Exception { - final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); - - // Simulate the a resumed activity set during - // {@link ActivityStack#resumeTopActivityUncheckedLocked}. - mSupervisor.inResumeTopActivity = true; - r.setState(RESUMED, "testNoPauseDuringResumeTopActivity"); - - final boolean waiting = mStack.goToSleepIfPossible(false); - - // Ensure we report not being ready for sleep. - assertFalse(waiting); - - // Make sure the resumed activity is untouched. - assertEquals(mStack.getResumedActivity(), r); - } - @Test public void testResumedActivity() throws Exception { final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); @@ -478,28 +463,6 @@ public class ActivityStackTests extends ActivityTestsBase { return stack; } - @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(); @@ -540,4 +503,37 @@ public class ActivityStackTests extends ActivityTestsBase { assertTrue(mTask.mActivities.isEmpty()); assertTrue(mStack.getAllTasks().isEmpty()); } + + @Test + public void testShouldSleepActivities() throws Exception { + // When focused activity and keyguard is going away, we should not sleep regardless + // of the display state + verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/, + true /* displaySleeping */, false /* expected*/); + + // When not the focused stack, defer to display sleeping state. + verifyShouldSleepActivities(false /* focusedStack */, true /*keyguardGoingAway*/, + true /* displaySleeping */, true /* expected*/); + + // If keyguard is going away, defer to the display sleeping state. + verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/, + true /* displaySleeping */, true /* expected*/); + verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/, + false /* displaySleeping */, false /* expected*/); + } + + private void verifyShouldSleepActivities(boolean focusedStack, + boolean keyguardGoingAway, boolean displaySleeping, boolean expected) { + mSupervisor.mFocusedStack = focusedStack ? mStack : null; + + final ActivityDisplay display = mock(ActivityDisplay.class); + final KeyguardController keyguardController = mSupervisor.getKeyguardController(); + + doReturn(display).when(mSupervisor).getActivityDisplay(anyInt()); + doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway(); + doReturn(displaySleeping).when(display).isSleeping(); + + assertEquals(expected, mStack.shouldSleepActivities()); + } + } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index 3041a5f2cd55638de4818e7fb8ac250a7590acaf..c130592b4cd35c5928b5052fce8c4247e90e38ca 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -316,6 +316,7 @@ public class ActivityTestsBase { @Override final protected ActivityStackSupervisor createStackSupervisor() { final ActivityStackSupervisor supervisor = spy(createTestSupervisor()); + final KeyguardController keyguardController = mock(KeyguardController.class); // No home stack is set. doNothing().when(supervisor).moveHomeStackToFront(any()); @@ -330,6 +331,7 @@ public class ActivityTestsBase { doNothing().when(supervisor).scheduleIdleTimeoutLocked(any()); // unit test version does not handle launch wake lock doNothing().when(supervisor).acquireLaunchWakelock(); + doReturn(keyguardController).when(supervisor).getKeyguardController(); supervisor.initialize(); 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 24566fcf8f0d024e8505430e3b73ba2f88de7fcb..376f5b1937164792083abe773a9b221c217f782c 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); @@ -251,6 +253,50 @@ public class RecentTasksTest extends ActivityTestsBase { assertTrue(mCallbacksRecorder.removed.isEmpty()); } + @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/autofill/AutofillManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c348e70bb37565b5e70ee5f4d193c75058b10982 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java @@ -0,0 +1,114 @@ +/* + * 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 com.android.server.autofill; + +import static com.android.server.autofill.AutofillManagerService.getWhitelistedCompatModePackages; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.Map; + +@RunWith(JUnit4.class) +public class AutofillManagerServiceTest { + // TODO(b/74445943): temporary work around until P Development Preview 3 is branched + private static final boolean ADDS_DEFAULT_BUTTON = true; + + @Test + public void testGetWhitelistedCompatModePackages_null() { + assertThat(getWhitelistedCompatModePackages(null)).isNull(); + } + + @Test + public void testGetWhitelistedCompatModePackages_empty() { + assertThat(getWhitelistedCompatModePackages("")).isNull(); + } + + @Test + public void testGetWhitelistedCompatModePackages_onePackageNoUrls() { + if (ADDS_DEFAULT_BUTTON) { + final Map result = + getWhitelistedCompatModePackages("one_is_the_loniest_package"); + assertThat(result).hasSize(1); + assertThat(result.get("one_is_the_loniest_package")).asList() + .containsExactly("url_bar", "location_bar_edit_text"); + } else { + assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package")) + .containsExactly("one_is_the_loniest_package", null); + } + } + + @Test + public void testGetWhitelistedCompatModePackages_onePackageMissingEndDelimiter() { + assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package[")).isEmpty(); + } + + @Test + public void testGetWhitelistedCompatModePackages_onePackageOneUrl() { + final Map result = + getWhitelistedCompatModePackages("one_is_the_loniest_package[url]"); + assertThat(result).hasSize(1); + assertThat(result.get("one_is_the_loniest_package")).asList().containsExactly("url"); + } + + @Test + public void testGetWhitelistedCompatModePackages_onePackageMultipleUrls() { + final Map result = + getWhitelistedCompatModePackages("one_is_the_loniest_package[4,5,8,15,16,23,42]"); + assertThat(result).hasSize(1); + assertThat(result.get("one_is_the_loniest_package")).asList() + .containsExactly("4", "5", "8", "15", "16", "23", "42"); + } + + @Test + public void testGetWhitelistedCompatModePackages_multiplePackagesOneInvalid() { + final Map result = getWhitelistedCompatModePackages("one:two["); + assertThat(result).hasSize(1); + if (ADDS_DEFAULT_BUTTON) { + assertThat(result.get("one")).asList() + .containsExactly("url_bar", "location_bar_edit_text"); + } else { + assertThat(result.get("one")).isNull(); + } + } + + @Test + public void testGetWhitelistedCompatModePackages_multiplePackagesMultipleUrls() { + final Map result = + getWhitelistedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]"); + assertThat(result).hasSize(3); + assertThat(result.get("p1")).asList().containsExactly("p1u1"); + if (ADDS_DEFAULT_BUTTON) { + assertThat(result.get("p2")).asList() + .containsExactly("url_bar", "location_bar_edit_text"); + } else { + assertThat(result.get("p2")).isNull(); + } + assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2"); + } + + @Test + public void testGetWhitelistedCompatModePackages_threePackagesOneInvalid() { + final Map result = + getWhitelistedCompatModePackages("p1[p1u1]:p2[:p3[p3u1,p3u2]"); + assertThat(result).hasSize(2); + assertThat(result.get("p1")).asList().containsExactly("p1u1"); + assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2"); + } +} diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java index 613d0afea183e547cff45b1c8b6a967ec7ed75c9..10a21fdf6f3e3f0ea02573a74afabd11cce730f9 100644 --- a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java +++ b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java @@ -436,6 +436,11 @@ public class PackageManagerStub extends PackageManager { return null; } + @Override + public ResolveInfo resolveServiceAsUser(Intent intent, int flags, int userId) { + return null; + } + @Override public List queryIntentServices(Intent intent, int flags) { return null; 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 86c83d6707b6b79f192613fc4df01d6d454c29c7..d37db20f05b74a8bca3c41efd11f4667bb4e58ba 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 0cdf04bda2d07856cefd6b3a2df16d7c66525cf9..5f052ceb2e26b8c684bea1e78b2ae8d0e1f9a3fe 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 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 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 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 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 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 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 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 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 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 bundleCaptor = ArgumentCaptor.forClass(Bundle.class); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index e8170ee4ad3966f64abf5db07d72d09c70d49b57..d2fb1cab347928ae25aef30630aa1e8682258aa5 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -4738,7 +4738,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testOverrideApnAPIsFailWithPO() throws Exception { setupProfileOwner(); - ApnSetting apn = (new ApnSetting.Builder()).build(); + ApnSetting apn = (new ApnSetting.Builder()) + .setApnName("test") + .setEntryName("test") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT) + .build(); assertExpectException(SecurityException.class, null, () -> dpm.addOverrideApn(admin1, apn)); assertExpectException(SecurityException.class, null, () -> diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java index 92ea7665669341d77e52ee9e13b027c342a595e2..17e58325734fb568d707d80a71fb4544d542fe37 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java @@ -22,6 +22,7 @@ import com.android.server.pm.UserRestrictionsUtils; import android.content.ComponentName; import android.content.Intent; +import android.os.BaseBundle; import android.os.Bundle; import android.os.UserHandle; import android.util.ArraySet; @@ -92,7 +93,10 @@ public class MockUtils { public boolean matches(Object item) { if (item == null) return false; if (!intent.filterEquals((Intent) item)) return false; - return intent.getExtras().kindofEquals(((Intent) item).getExtras()); + BaseBundle extras = intent.getExtras(); + BaseBundle itemExtras = ((Intent) item).getExtras(); + return (extras == itemExtras) || (extras != null && + extras.kindofEquals(itemExtras)); } @Override public void describeTo(Description description) { 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 1211f00b1252bb59bd01bb7d9934538a8edb60ac..2f2afd71706c376012f82207b6ca8a5c09b99514 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/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java index e8648701bd0dd36a7058e4e216fe804ac0c79729..96f81606a985c7d72c2d903e7ec2a30bdb7a5245 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java @@ -43,6 +43,7 @@ import android.test.AndroidTestCase; import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockSettingsInternal; import com.android.server.LocalServices; import org.mockito.invocation.InvocationOnMock; @@ -67,6 +68,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { private ArrayList mPrimaryUserProfiles = new ArrayList<>(); LockSettingsService mService; + LockSettingsInternal mLocalService; MockLockSettingsContext mContext; LockSettingsStorageTestable mStorage; @@ -95,6 +97,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { mDevicePolicyManager = mock(DevicePolicyManager.class); mDevicePolicyManagerInternal = mock(DevicePolicyManagerInternal.class); + LocalServices.removeServiceForTest(LockSettingsInternal.class); LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); LocalServices.addService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal); @@ -146,6 +149,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { // Adding a fake Device Owner app which will enable escrow token support in LSS. when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn( new ComponentName("com.dummy.package", ".FakeDeviceOwner")); + mLocalService = LocalServices.getService(LockSettingsInternal.class); } private UserInfo installChildProfile(int profileId) { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index 294c3e99ad7ec69805fbadc2152b1e27974cae56..e9f9800f2198c1a41a4f664b747d92070a126deb 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -300,14 +300,14 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); - long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); - assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode(); - assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, + mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); // Verify DPM gets notified about new device lock @@ -329,16 +329,16 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); - long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); - assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode(); - assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, handle, - TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); - mService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, + mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, + handle, TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); + mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( @@ -355,18 +355,19 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); - long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); - assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode(); - assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); mService.setLockCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, PASSWORD, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); - mService.setLockCredentialWithToken(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - handle, TOKEN.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); + mLocalService.setLockCredentialWithToken(NEWPASSWORD, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, TOKEN.getBytes(), + PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) @@ -378,8 +379,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { throws RemoteException { final String TOKEN = "some-high-entropy-secure-token"; enableSyntheticPassword(); - long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); - assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertTrue(hasSyntheticPassword(PRIMARY_USER_ID)); } @@ -388,8 +389,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { throws RemoteException { final String TOKEN = "some-high-entropy-secure-token"; initializeCredentialUnderSP(null, PRIMARY_USER_ID); - long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); - assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertTrue(hasSyntheticPassword(PRIMARY_USER_ID)); } @@ -404,15 +405,15 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); enableSyntheticPassword(); - long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); // Token not activated immediately since user password exists - assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); // Activate token (password gets migrated to SP at the same time) assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); // Verify token is activated - assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); } public void testPasswordData_serializeDeserialize() { 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 e40e3a42ee53df1b33401b4a9c11d4254a7f124e..69796b33c2eb7ccce9fb7b78274240071802c7ca 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 @@ -30,6 +30,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.never; @@ -42,11 +43,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; @@ -238,10 +241,8 @@ public class KeySyncTaskTest { } @Test - public void run_doesNotSendAnythingIfNoRecoveryAgentPendingIntentRegistered() throws Exception { + public void run_doesNotSendAnythingIfNoDeviceIdIsSet() throws Exception { SecretKey applicationKey = generateKey(); - mRecoverableKeyStoreDb.setServerParams( - TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE); mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID); mRecoverableKeyStoreDb.insertKey( TEST_USER_ID, @@ -250,6 +251,7 @@ public class KeySyncTaskTest { WrappedKey.fromSecretKey(mEncryptKey, applicationKey)); mRecoverableKeyStoreDb.setRecoveryServicePublicKey( TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic()); + when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true); mKeySyncTask.run(); @@ -257,21 +259,18 @@ public class KeySyncTaskTest { } @Test - public void run_doesNotSendAnythingIfNoDeviceIdIsSet() throws Exception { - SecretKey applicationKey = generateKey(); + public void run_stillCreatesSnapshotIfNoRecoveryAgentPendingIntentRegistered() + throws Exception { + mRecoverableKeyStoreDb.setServerParams( + TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE); mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID); - mRecoverableKeyStoreDb.insertKey( - TEST_USER_ID, - TEST_RECOVERY_AGENT_UID, - TEST_APP_KEY_ALIAS, - WrappedKey.fromSecretKey(mEncryptKey, applicationKey)); + addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS); mRecoverableKeyStoreDb.setRecoveryServicePublicKey( TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic()); - when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true); mKeySyncTask.run(); - assertNull(mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID)); + assertNotNull(mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID)); } @Test @@ -500,7 +499,7 @@ public class KeySyncTaskTest { } @Test - public void run_doesNotSendKeyToNonregisteredAgent() throws Exception { + public void run_notifiesNonregisteredAgent() throws Exception { mRecoverableKeyStoreDb.setRecoveryServicePublicKey( TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic()); mRecoverableKeyStoreDb.setRecoveryServicePublicKey( @@ -512,8 +511,35 @@ public class KeySyncTaskTest { mKeySyncTask.run(); verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID); - verify(mSnapshotListenersStorage, never()). - recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID2); + verify(mSnapshotListenersStorage).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) diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorageTest.java index b9c176452b9e9795f63e47bccdbf5ac4d7e71f6d..acc200fa81adf9687301a7f44e8021bf4dde0dab 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorageTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorageTest.java @@ -4,7 +4,10 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -12,10 +15,18 @@ import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + @SmallTest @RunWith(AndroidJUnit4.class) public class RecoverySnapshotListenersStorageTest { + private static final String TEST_INTENT_ACTION = + "com.android.server.locksettings.recoverablekeystore.RECOVERY_SNAPSHOT_TEST_ACTION"; + + private static final int TEST_TIMEOUT_SECONDS = 1; + private final RecoverySnapshotListenersStorage mStorage = new RecoverySnapshotListenersStorage(); @@ -28,10 +39,55 @@ public class RecoverySnapshotListenersStorageTest { public void hasListener_isTrueForRegisteredUid() { int recoveryAgentUid = 1000; PendingIntent intent = PendingIntent.getBroadcast( - InstrumentationRegistry.getTargetContext(), /*requestCode=*/1, + InstrumentationRegistry.getTargetContext(), /*requestCode=*/ 1, new Intent(), /*flags=*/ 0); mStorage.setSnapshotListener(recoveryAgentUid, intent); assertTrue(mStorage.hasListener(recoveryAgentUid)); } + + @Test + public void setSnapshotListener_invokesIntentImmediatelyIfPreviouslyNotified() + throws Exception { + Context context = InstrumentationRegistry.getTargetContext(); + int recoveryAgentUid = 1000; + mStorage.recoverySnapshotAvailable(recoveryAgentUid); + PendingIntent intent = PendingIntent.getBroadcast( + context, /*requestCode=*/ 0, new Intent(TEST_INTENT_ACTION), /*flags=*/0); + CountDownLatch latch = new CountDownLatch(1); + context.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + context.unregisterReceiver(this); + latch.countDown(); + } + }, new IntentFilter(TEST_INTENT_ACTION)); + + mStorage.setSnapshotListener(recoveryAgentUid, intent); + + assertTrue(latch.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS)); + } + + @Test + public void setSnapshotListener_doesNotRepeatedlyInvokeListener() throws Exception { + Context context = InstrumentationRegistry.getTargetContext(); + int recoveryAgentUid = 1000; + mStorage.recoverySnapshotAvailable(recoveryAgentUid); + PendingIntent intent = PendingIntent.getBroadcast( + context, /*requestCode=*/ 0, new Intent(TEST_INTENT_ACTION), /*flags=*/0); + CountDownLatch latch = new CountDownLatch(2); + BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + latch.countDown(); + } + }; + context.registerReceiver(broadcastReceiver, new IntentFilter(TEST_INTENT_ACTION)); + + mStorage.setSnapshotListener(recoveryAgentUid, intent); + mStorage.setSnapshotListener(recoveryAgentUid, intent); + + assertFalse(latch.await(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS)); + context.unregisterReceiver(broadcastReceiver); + } } 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 dfb2dbf884f07122d39c2333e12df33b09738675..8b01d972f7e55ee7f526d4966276d272b587ec6a 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 @@ -341,6 +341,30 @@ public class RecoverableKeyStoreDbTest { .isEqualTo(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE); } + @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; 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 51d27fe016f0bc671a4224ede838d6d21e7bdbf8..197475032ea8721b356c7031b5a9bfa00a40b266 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/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index c491601fee1f58dd680a490a9d8ffcd438caff1b..2f6e2c2ae6a3692721c41f36219d6b19fb67d3ea 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -27,8 +27,10 @@ import android.content.pm.ServiceInfo; import android.content.pm.Signature; import android.os.Bundle; import android.os.Parcel; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.MediumTest; +import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import android.test.suitebuilder.annotation.MediumTest; import java.io.File; import java.lang.reflect.Array; @@ -126,6 +128,8 @@ public class PackageParserTest { } @Test + @SmallTest + @Presubmit public void test_roundTripKnownFields() throws Exception { PackageParser.Package pkg = new PackageParser.Package("foo"); setKnownFields(pkg); @@ -266,6 +270,9 @@ public class PackageParserTest { assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType); assertEquals(a.mRequiredAccountType, b.mRequiredAccountType); assertEquals(a.mOverlayTarget, b.mOverlayTarget); + assertEquals(a.mOverlayCategory, b.mOverlayCategory); + assertEquals(a.mOverlayPriority, b.mOverlayPriority); + assertEquals(a.mOverlayIsStatic, b.mOverlayIsStatic); assertEquals(a.mSigningDetails.publicKeys, b.mSigningDetails.publicKeys); assertEquals(a.mUpgradeKeySets, b.mUpgradeKeySets); assertEquals(a.mKeySetMapping, b.mKeySetMapping); @@ -524,6 +531,15 @@ public class PackageParserTest { pkg.mCompileSdkVersionCodename = "foo23"; pkg.mCompileSdkVersion = 100; pkg.mVersionCodeMajor = 100; + + pkg.mOverlayCategory = "foo24"; + pkg.mOverlayIsStatic = true; + + pkg.baseHardwareAccelerated = true; + pkg.coreApp = true; + pkg.mRequiredForAllUsers = true; + pkg.visibleToInstantApps = true; + pkg.use32bitAbi = true; } private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception { @@ -532,6 +548,7 @@ public class PackageParserTest { Set nonSerializedFields = new HashSet<>(); nonSerializedFields.add("mExtras"); nonSerializedFields.add("packageUsageTimeMillis"); + nonSerializedFields.add("isStub"); for (Field f : fields) { final Class fieldType = f.getType(); @@ -560,6 +577,10 @@ public class PackageParserTest { // int fields: Check that they're set to 100. int value = (int) f.get(pkg); assertEquals("Bad value for field: " + f, 100, value); + } else if (fieldType == boolean.class) { + // boolean fields: Check that they're set to true. + boolean value = (boolean) f.get(pkg); + assertEquals("Bad value for field: " + f, true, value); } else { // All other fields: Check that they're set. Object o = f.get(pkg); 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 845e05d284655070197c08c21871b53dece275cf..7815004c18f964348b6da6a7f5b0f2df6dc86a44 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 29c98dcf5228df175afe17fffb242ce265ff5cf9..cd7feea08caa4de39657319b09fae31d152a6bc2 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 c016e6104755658b27ea0354f76b32ebc701dbc8..1ac7cb86f867a40dd91b15cd4816307a0646f00c 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 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 stored1 = BackupUtils.hashSignatureArray(Arrays.asList( - "abc".getBytes())); - final ArrayList 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 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 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 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 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 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 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 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 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 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 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 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 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/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java index 5de393c7ae2b85fab23e307081422b889a7216e7..56ba047338a79c86121593058165560da7e154f3 100644 --- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java +++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java @@ -25,6 +25,8 @@ import android.view.DisplayCutout; import android.view.IApplicationToken; import android.view.WindowManager; +import com.android.server.wm.utils.WmDisplayCutout; + public class FakeWindowState implements WindowManagerPolicy.WindowState { public final Rect parentFrame = new Rect(); @@ -36,7 +38,7 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { public final Rect stableFrame = new Rect(); public Rect outsetFrame = new Rect(); - public DisplayCutout displayCutout; + public WmDisplayCutout displayCutout; public WindowManager.LayoutParams attrs; public int displayId; @@ -61,7 +63,8 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { @Override public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, - @Nullable Rect outsetFrame, DisplayCutout displayCutout) { + @Nullable Rect outsetFrame, WmDisplayCutout displayCutout, + boolean parentFrameWasClippedByDisplayCutout) { this.parentFrame.set(parentFrame); this.displayFrame.set(displayFrame); this.overscanFrame.set(overlayFrame); diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java index 1d4348c0b6d4444f7965bc803b7c0aff09adb021..195dd39758df0a3419f90289119b8f4a9ba0beb7 100644 --- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java +++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java @@ -41,6 +41,7 @@ import android.os.IBinder; import android.os.UserHandle; import android.support.test.InstrumentationRegistry; import android.testing.TestableResources; +import android.util.Pair; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; @@ -53,6 +54,7 @@ import android.view.accessibility.IAccessibilityManager; import com.android.server.policy.keyguard.KeyguardServiceDelegate; import com.android.server.wm.DisplayFrames; +import com.android.server.wm.utils.WmDisplayCutout; import org.junit.Before; @@ -98,8 +100,9 @@ public class PhoneWindowManagerTestBase { } private void updateDisplayFrames() { - DisplayInfo info = displayInfoForRotation(mRotation, mHasDisplayCutout); - mFrames = new DisplayFrames(Display.DEFAULT_DISPLAY, info); + Pair info = displayInfoAndCutoutForRotation(mRotation, + mHasDisplayCutout); + mFrames = new DisplayFrames(Display.DEFAULT_DISPLAY, info.first, info.second); } public void addStatusBar() { @@ -146,19 +149,26 @@ public class PhoneWindowManagerTestBase { } public static DisplayInfo displayInfoForRotation(int rotation, boolean withDisplayCutout) { + return displayInfoAndCutoutForRotation(rotation, withDisplayCutout).first; + } + public static Pair displayInfoAndCutoutForRotation(int rotation, + boolean withDisplayCutout) { DisplayInfo info = new DisplayInfo(); + WmDisplayCutout cutout = null; final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270; info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH; info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT; info.rotation = rotation; if (withDisplayCutout) { - info.displayCutout = displayCutoutForRotation(rotation) - .computeSafeInsets(info.logicalWidth, info.logicalHeight); + cutout = WmDisplayCutout.computeSafeInsets( + displayCutoutForRotation(rotation), info.logicalWidth, + info.logicalHeight); + info.displayCutout = cutout.getDisplayCutout(); } else { info.displayCutout = null; } - return info; + return Pair.create(info, cutout); } private static DisplayCutout displayCutoutForRotation(int rotation) { diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java index f7112d43443b19c11e75de264a101aad59cb64d7..0f3ca03fa6d705bf62eb5b3052bbee9b28b5e40b 100644 --- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java +++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java @@ -15,8 +15,6 @@ */ package com.android.server.power.batterysaver; -import static com.android.server.power.batterysaver.BatterySavingStats.SEND_TRON_EVENTS; - import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -105,9 +103,23 @@ public class BatterySavingStatsTest { public MetricsLogger mMetricsLogger = mock(MetricsLogger.class); + private boolean sendTronEvents; + @Test - public void testAll() { + public void testAll_withTron() { + sendTronEvents = true; + checkAll(); + } + + @Test + public void testAll_noTron() { + sendTronEvents = false; + checkAll(); + } + + private void checkAll() { final BatterySavingStatsTestable target = new BatterySavingStatsTestable(); + target.setSendTronLog(sendTronEvents); target.assertDumpable(); @@ -229,7 +241,7 @@ public class BatterySavingStatsTest { private void assertLog(boolean batterySaver, boolean interactive, long deltaTimeMs, int deltaBatteryLevelUa, int deltaBatteryLevelPercent) { - if (SEND_TRON_EVENTS) { + if (sendTronEvents) { ArgumentCaptor ac = ArgumentCaptor.forClass(LogMaker.class); verify(mMetricsLogger, times(1)).write(ac.capture()); @@ -251,9 +263,22 @@ public class BatterySavingStatsTest { } } + + @Test + public void testMetricsLogger_withTron() { + sendTronEvents = true; + checkMetricsLogger(); + } + @Test - public void testMetricsLogger() { + public void testMetricsLogger_noTron() { + sendTronEvents = false; + checkMetricsLogger(); + } + + private void checkMetricsLogger() { final BatterySavingStatsTestable target = new BatterySavingStatsTestable(); + target.setSendTronLog(sendTronEvents); target.advanceClock(1); target.drainBattery(1000); diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java new file mode 100644 index 0000000000000000000000000000000000000000..6b52ee5f44081785d6349e642c57ca6759d77cae --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java @@ -0,0 +1,256 @@ +/* + * 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 com.android.server.usage; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.app.PendingIntent; +import android.os.HandlerThread; +import android.os.Looper; +import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +@MediumTest +public class AppTimeLimitControllerTests { + + private static final String PKG_SOC1 = "package.soc1"; + private static final String PKG_SOC2 = "package.soc2"; + private static final String PKG_GAME1 = "package.game1"; + private static final String PKG_GAME2 = "package.game2"; + private static final String PKG_PROD = "package.prod"; + + private static final int UID = 10100; + private static final int USER_ID = 10; + private static final int OBS_ID1 = 1; + private static final int OBS_ID2 = 2; + private static final int OBS_ID3 = 3; + + private static final long TIME_30_MIN = 30 * 60_1000L; + private static final long TIME_10_MIN = 10 * 60_1000L; + + private static final String[] GROUP1 = { + PKG_SOC1, PKG_GAME1, PKG_PROD + }; + + private static final String[] GROUP_SOC = { + PKG_SOC1, PKG_SOC2 + }; + + private static final String[] GROUP_GAME = { + PKG_GAME1, PKG_GAME2 + }; + + private final CountDownLatch mCountDownLatch = new CountDownLatch(1); + + private AppTimeLimitController mController; + + private HandlerThread mThread; + + private long mUptimeMillis; + + AppTimeLimitController.OnLimitReachedListener mListener + = new AppTimeLimitController.OnLimitReachedListener() { + + @Override + public void onLimitReached(int observerId, int userId, long timeLimit, long timeElapsed, + PendingIntent callbackIntent) { + mCountDownLatch.countDown(); + } + }; + + class MyAppTimeLimitController extends AppTimeLimitController { + MyAppTimeLimitController(AppTimeLimitController.OnLimitReachedListener listener, + Looper looper) { + super(listener, looper); + } + + @Override + protected long getUptimeMillis() { + return mUptimeMillis; + } + } + + @Before + public void setUp() { + mThread = new HandlerThread("Test"); + mThread.start(); + mController = new MyAppTimeLimitController(mListener, mThread.getLooper()); + } + + @After + public void tearDown() { + mThread.quit(); + } + + /** Verify observer is added */ + @Test + public void testAddObserver() { + addObserver(OBS_ID1, GROUP1, TIME_30_MIN); + assertTrue("Observer wasn't added", hasObserver(OBS_ID1)); + addObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN); + assertTrue("Observer wasn't added", hasObserver(OBS_ID2)); + assertTrue("Observer wasn't added", hasObserver(OBS_ID1)); + } + + /** Verify observer is removed */ + @Test + public void testRemoveObserver() { + addObserver(OBS_ID1, GROUP1, TIME_30_MIN); + assertTrue("Observer wasn't added", hasObserver(OBS_ID1)); + mController.removeObserver(UID, OBS_ID1, USER_ID); + assertFalse("Observer wasn't removed", hasObserver(OBS_ID1)); + } + + /** Re-adding an observer should result in only one copy */ + @Test + public void testObserverReAdd() { + addObserver(OBS_ID1, GROUP1, TIME_30_MIN); + assertTrue("Observer wasn't added", hasObserver(OBS_ID1)); + addObserver(OBS_ID1, GROUP1, TIME_10_MIN); + assertTrue("Observer wasn't added", + mController.getObserverGroup(OBS_ID1, USER_ID).timeLimit == TIME_10_MIN); + mController.removeObserver(UID, OBS_ID1, USER_ID); + assertFalse("Observer wasn't removed", hasObserver(OBS_ID1)); + } + + /** Verify that usage across different apps within a group are added up */ + @Test + public void testAccumulation() throws Exception { + setTime(0L); + addObserver(OBS_ID1, GROUP1, TIME_30_MIN); + moveToForeground(PKG_SOC1); + // Add 10 mins + setTime(TIME_10_MIN); + moveToBackground(PKG_SOC1); + + long timeRemaining = mController.getObserverGroup(OBS_ID1, USER_ID).timeRemaining; + assertEquals(TIME_10_MIN * 2, timeRemaining); + + moveToForeground(PKG_SOC1); + setTime(TIME_10_MIN * 2); + moveToBackground(PKG_SOC1); + + timeRemaining = mController.getObserverGroup(OBS_ID1, USER_ID).timeRemaining; + assertEquals(TIME_10_MIN, timeRemaining); + + setTime(TIME_30_MIN); + + assertFalse(mCountDownLatch.await(100L, TimeUnit.MILLISECONDS)); + + // Add a different package in the group + moveToForeground(PKG_GAME1); + setTime(TIME_30_MIN + TIME_10_MIN); + moveToBackground(PKG_GAME1); + + assertEquals(0, mController.getObserverGroup(OBS_ID1, USER_ID).timeRemaining); + assertTrue(mCountDownLatch.await(100L, TimeUnit.MILLISECONDS)); + } + + /** Verify that time limit does not get triggered due to a different app */ + @Test + public void testTimeoutOtherApp() throws Exception { + setTime(0L); + addObserver(OBS_ID1, GROUP1, 4_000L); + moveToForeground(PKG_SOC2); + assertFalse(mCountDownLatch.await(6_000L, TimeUnit.MILLISECONDS)); + setTime(6_000L); + moveToBackground(PKG_SOC2); + assertFalse(mCountDownLatch.await(100L, TimeUnit.MILLISECONDS)); + } + + /** Verify the timeout message is delivered at the right time */ + @Test + public void testTimeout() throws Exception { + setTime(0L); + addObserver(OBS_ID1, GROUP1, 4_000L); + moveToForeground(PKG_SOC1); + setTime(6_000L); + assertTrue(mCountDownLatch.await(6_000L, TimeUnit.MILLISECONDS)); + moveToBackground(PKG_SOC1); + // Verify that the observer was removed + assertFalse(hasObserver(OBS_ID1)); + } + + /** If an app was already running, make sure it is partially counted towards the time limit */ + @Test + public void testAlreadyRunning() throws Exception { + setTime(TIME_10_MIN); + moveToForeground(PKG_GAME1); + setTime(TIME_30_MIN); + addObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN); + setTime(TIME_30_MIN + TIME_10_MIN); + moveToBackground(PKG_GAME1); + assertFalse(mCountDownLatch.await(1000L, TimeUnit.MILLISECONDS)); + + moveToForeground(PKG_GAME2); + setTime(TIME_30_MIN + TIME_30_MIN); + moveToBackground(PKG_GAME2); + assertTrue(mCountDownLatch.await(1000L, TimeUnit.MILLISECONDS)); + // Verify that the observer was removed + assertFalse(hasObserver(OBS_ID2)); + } + + /** If watched app is already running, verify the timeout callback happens at the right time */ + @Test + public void testAlreadyRunningTimeout() throws Exception { + setTime(0); + moveToForeground(PKG_SOC1); + setTime(TIME_10_MIN); + // 10 second time limit + addObserver(OBS_ID1, GROUP_SOC, 10_000L); + setTime(TIME_10_MIN + 5_000L); + // Shouldn't call back in 6 seconds + assertFalse(mCountDownLatch.await(6_000L, TimeUnit.MILLISECONDS)); + setTime(TIME_10_MIN + 10_000L); + // Should call back by 11 seconds (6 earlier + 5 now) + assertTrue(mCountDownLatch.await(5_000L, TimeUnit.MILLISECONDS)); + // Verify that the observer was removed + assertFalse(hasObserver(OBS_ID1)); + } + + private void moveToForeground(String packageName) { + mController.moveToForeground(packageName, "class", USER_ID); + } + + private void moveToBackground(String packageName) { + mController.moveToBackground(packageName, "class", USER_ID); + } + + private void addObserver(int observerId, String[] packages, long timeLimit) { + mController.addObserver(UID, observerId, packages, timeLimit, null, USER_ID); + } + + /** Is there still an observer by that id */ + private boolean hasObserver(int observerId) { + return mController.getObserverGroup(observerId, USER_ID) != null; + } + + private void setTime(long time) { + mUptimeMillis = time; + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8b78f10b0b5b7220e4d897b01c06ec7c9d113eb9 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java @@ -0,0 +1,91 @@ +/* + * 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 com.android.server.wm; + +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.FlakyTest; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for the {@link TaskStack} class. + * + * Build/Install/Run: + * atest FrameworksServicesTests:com.android.server.wm.AnimatingAppWindowTokenRegistryTest + */ +@SmallTest +@Presubmit +@FlakyTest(detail = "Promote once confirmed non-flaky") +@RunWith(AndroidJUnit4.class) +public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase { + + @Mock + AnimationAdapter mAdapter; + + @Mock + Runnable mMockEndDeferFinishCallback1; + @Mock + Runnable mMockEndDeferFinishCallback2; + @Before + public void setUp() throws Exception { + super.setUp(); + MockitoAnnotations.initMocks(this); + } + + @Test + public void testDeferring() throws Exception { + final AppWindowToken window1 = createAppWindowToken(mDisplayContent, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); + final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD, + "window2").mAppToken; + final AnimatingAppWindowTokenRegistry registry = + window1.getStack().getAnimatingAppWindowTokenRegistry(); + + window1.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */); + window2.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */); + assertTrue(window1.isSelfAnimating()); + assertTrue(window2.isSelfAnimating()); + + // Make sure that first animation finish is deferred, second one is not deferred, and first + // one gets cancelled. + assertTrue(registry.notifyAboutToFinish(window1, mMockEndDeferFinishCallback1)); + assertFalse(registry.notifyAboutToFinish(window2, mMockEndDeferFinishCallback2)); + verify(mMockEndDeferFinishCallback1).run(); + verifyZeroInteractions(mMockEndDeferFinishCallback2); + } +} 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 76e4e895278ea2ecc1e75b325d0122fff0bf44f0..e0645b1f4bfb0cda17a661d431dc8e2126ac162b 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 @@ -175,6 +172,33 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent)); } + @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 = diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java index 8d5214a86d847c7571168948844829e5e66e62f5..0c63cd270d39ee5e75637018e5768cfa678f698a 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java @@ -20,6 +20,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import android.platform.test.annotations.Presubmit; +import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.Surface; @@ -29,12 +30,14 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; +import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.TRANSIT_UNSET; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -43,7 +46,7 @@ import static org.junit.Assert.assertTrue; * Tests for the {@link AppWindowToken} class. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests + * atest FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests */ @SmallTest // TODO: b/68267650 @@ -231,4 +234,20 @@ public class AppWindowTokenTests extends WindowTestsBase { mToken.finishRelaunching(); assertFalse(mToken.containsShowWhenLockedWindow() || mToken.containsDismissKeyguardWindow()); } + + @Test + @FlakyTest(detail = "Promote once confirmed non-flaky") + public void testStuckExitingWindow() throws Exception { + final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, + "closingWindow"); + closingWindow.mAnimatingExit = true; + closingWindow.mRemoveOnExit = true; + closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET, + true /* performLayout */, false /* isVoiceInteraction */); + + // We pretended that we were running an exit animation, but that should have been cleared up + // by changing visibility of AppWindowToken + closingWindow.removeIfPossible(); + assertTrue(closingWindow.mRemoved); + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java index 064e077ee9edbf082f97aeb495a3c3d442358152..b645700abb794961342b03a351b5e216cff9d14f 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -31,9 +31,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; -import android.support.test.filters.FlakyTest; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,6 +52,8 @@ import android.view.DisplayCutout; import android.view.MotionEvent; import android.view.Surface; +import com.android.server.wm.utils.WmDisplayCutout; + import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -300,7 +304,6 @@ public class DisplayContentTests extends WindowTestsBase { } @Test - @FlakyTest(bugId = 37908381) public void testFocusedWindowMultipleDisplays() throws Exception { // Create a focusable window and check that focus is calculated correctly final WindowState window1 = @@ -398,8 +401,9 @@ public class DisplayContentTests extends WindowTestsBase { dc.mInitialDisplayWidth = 200; dc.mInitialDisplayHeight = 400; Rect r = new Rect(80, 0, 120, 10); - final DisplayCutout cutout = fromBoundingRect(r.left, r.top, r.right, r.bottom) - .computeSafeInsets(200, 400); + final DisplayCutout cutout = new WmDisplayCutout( + fromBoundingRect(r.left, r.top, r.right, r.bottom), null) + .computeSafeInsets(200, 400).getDisplayCutout(); dc.mInitialDisplayCutout = cutout; dc.setRotation(Surface.ROTATION_0); @@ -416,16 +420,18 @@ public class DisplayContentTests extends WindowTestsBase { dc.mInitialDisplayWidth = 200; dc.mInitialDisplayHeight = 400; Rect r1 = new Rect(80, 0, 120, 10); - final DisplayCutout cutout = fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom) - .computeSafeInsets(200, 400); + final DisplayCutout cutout = new WmDisplayCutout( + fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom), null) + .computeSafeInsets(200, 400).getDisplayCutout(); dc.mInitialDisplayCutout = cutout; dc.setRotation(Surface.ROTATION_90); dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo. final Rect r = new Rect(0, 80, 10, 120); - assertEquals(fromBoundingRect(r.left, r.top, r.right, r.bottom) - .computeSafeInsets(400, 200), dc.getDisplayInfo().displayCutout); + assertEquals(new WmDisplayCutout( + fromBoundingRect(r.left, r.top, r.right, r.bottom), null) + .computeSafeInsets(400, 200).getDisplayCutout(), dc.getDisplayInfo().displayCutout); } } @@ -454,6 +460,18 @@ public class DisplayContentTests extends WindowTestsBase { SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation()); } + @Test + public void testDisableDisplayInfoOverrideFromWindowManager() { + final DisplayContent dc = createNewDisplay(); + + assertTrue(dc.mShouldOverrideDisplayConfiguration); + sWm.dontOverrideDisplayInfo(dc.getDisplayId()); + + assertFalse(dc.mShouldOverrideDisplayConfiguration); + verify(sWm.mDisplayManagerInternal, times(1)) + .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null); + } + private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth, int expectedBaseHeight, int expectedBaseDensity) { assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth); diff --git a/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..96745fa5956ed111f66fc72e6cc7d1035fcfe141 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java @@ -0,0 +1,63 @@ +package com.android.server.wm; + +import static android.view.Display.DEFAULT_DISPLAY; + +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.view.IPinnedStackListener; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class PinnedStackControllerTest extends WindowTestsBase { + + @Mock private IPinnedStackListener mIPinnedStackListener; + @Mock private IPinnedStackListener.Stub mIPinnedStackListenerStub; + + @Before + public void setUp() throws Exception { + super.setUp(); + MockitoAnnotations.initMocks(this); + when(mIPinnedStackListener.asBinder()).thenReturn(mIPinnedStackListenerStub); + } + + @Test + public void setShelfHeight_shelfVisibilityChangedTriggered() throws RemoteException { + sWm.mSupportsPictureInPicture = true; + sWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener); + + verify(mIPinnedStackListener).onImeVisibilityChanged(false, 0); + verify(mIPinnedStackListener).onShelfVisibilityChanged(false, 0); + verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false), + eq(false), anyInt()); + verify(mIPinnedStackListener).onActionsChanged(any()); + verify(mIPinnedStackListener).onMinimizedStateChanged(anyBoolean()); + + reset(mIPinnedStackListener); + + final int SHELF_HEIGHT = 300; + + sWm.setShelfHeight(true, SHELF_HEIGHT); + verify(mIPinnedStackListener).onShelfVisibilityChanged(true, SHELF_HEIGHT); + verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false), + eq(true), anyInt()); + verify(mIPinnedStackListener, never()).onImeVisibilityChanged(anyBoolean(), anyInt()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java index b36c7d91c807a92dcf436c2b4db5a1205bac2089..edac8a5202d7c9ae734983032e6e36d1d4bf149c 100644 --- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java @@ -169,6 +169,7 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase { verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L)); } + @FlakyTest(bugId = 74780584) @Test public void testDeferStartingAnimations() throws Exception { mSurfaceAnimationRunner.deferStartingAnimations(); diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java index a120eba623a3caf927299aa1dffc932f7bbff257..650687245858735ab9e85b904d8ce50c26274c57 100644 --- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import android.platform.test.annotations.Presubmit; +import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.SurfaceControl; @@ -64,6 +65,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { private SurfaceSession mSession = new SurfaceSession(); private MyAnimatable mAnimatable; private MyAnimatable mAnimatable2; + private DeferFinishAnimatable mDeferFinishAnimatable; @Before public void setUp() throws Exception { @@ -71,6 +73,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { MockitoAnnotations.initMocks(this); mAnimatable = new MyAnimatable(); mAnimatable2 = new MyAnimatable(); + mDeferFinishAnimatable = new DeferFinishAnimatable(); } @Test @@ -166,6 +169,29 @@ public class SurfaceAnimatorTest extends WindowTestsBase { verify(mTransaction).destroy(eq(leash)); } + @Test + @FlakyTest(detail = "Promote once confirmed non-flaky") + public void testDeferFinish() throws Exception { + + // Start animation + mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, + true /* hidden */); + final ArgumentCaptor callbackCaptor = ArgumentCaptor.forClass( + OnAnimationFinishedCallback.class); + assertAnimating(mDeferFinishAnimatable); + verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture()); + + // Finish the animation but then make sure we are deferring. + callbackCaptor.getValue().onAnimationFinished(mSpec); + assertAnimating(mDeferFinishAnimatable); + + // Now end defer finishing. + mDeferFinishAnimatable.endDeferFinishCallback.run(); + assertNotAnimating(mAnimatable2); + assertTrue(mDeferFinishAnimatable.mFinishedCallbackCalled); + verify(mTransaction).destroy(eq(mDeferFinishAnimatable.mLeash)); + } + private void assertAnimating(MyAnimatable animatable) { assertTrue(animatable.mSurfaceAnimator.isAnimating()); assertNotNull(animatable.mSurfaceAnimator.getAnimation()); @@ -254,4 +280,15 @@ public class SurfaceAnimatorTest extends WindowTestsBase { private final Runnable mFinishedCallback = () -> mFinishedCallbackCalled = true; } + + private class DeferFinishAnimatable extends MyAnimatable { + + Runnable endDeferFinishCallback; + + @Override + public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { + this.endDeferFinishCallback = endDeferFinishCallback; + return true; + } + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java index 96fbc14022964a684e6ed63f32cff347d60cecf7..80cbf2aae3f0547a958d3174ba91487d9c0e028b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java @@ -42,7 +42,7 @@ import java.io.File; /** * Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader} * - * runtest frameworks-services -c com.android.server.wm.TaskSnapshotPersisterLoaderTest + * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest */ @MediumTest @Presubmit @@ -162,6 +162,23 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa assertNull(snapshotNotExist); } + @Test + public void testIsRealSnapshotPersistAndLoadSnapshot() { + TaskSnapshot a = createSnapshot(1f /* scale */, true /* isRealSnapshot */); + TaskSnapshot b = createSnapshot(1f /* scale */, false /* isRealSnapshot */); + assertTrue(a.isRealSnapshot()); + assertFalse(b.isRealSnapshot()); + mPersister.persistSnapshot(1, mTestUserId, a); + mPersister.persistSnapshot(2, mTestUserId, b); + mPersister.waitForQueueEmpty(); + final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */); + final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */); + assertNotNull(snapshotA); + assertNotNull(snapshotB); + assertTrue(snapshotA.isRealSnapshot()); + assertFalse(snapshotB.isRealSnapshot()); + } + @Test public void testRemoveObsoleteFiles() { mPersister.persistSnapshot(1, mTestUserId, createSnapshot()); diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java index b49a0fdf8f38c81143713eaf7bd7ee11d955ea4a..2ad5bf4040521bcad9f5aca1ea5fabe48897a982 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -84,12 +84,16 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { } TaskSnapshot createSnapshot(float scale) { + return createSnapshot(scale, true /* isRealSnapshot */); + } + + TaskSnapshot createSnapshot(float scale, boolean isRealSnapshot) { final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY); Canvas c = buffer.lockCanvas(); c.drawColor(Color.RED); buffer.unlockCanvasAndPost(c); return new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, TEST_INSETS, - scale < 1f /* reducedResolution */, scale); + scale < 1f /* reducedResolution */, scale, isRealSnapshot); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index 4288eac0faa94f88244871a8e306e55d447292f4..d5334babc1a6cb7bffa33dbb2e6f07e1a21037d5 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -60,7 +60,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888, GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER); final TaskSnapshot snapshot = new TaskSnapshot(buffer, - ORIENTATION_PORTRAIT, contentInsets, false, 1.0f); + ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */); mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test", Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds, ORIENTATION_PORTRAIT); 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 6784e302a5c465d2d3279387a10817db5ae0244e..6d9167fda585265c62c6130fb8adc66fb818ca3e 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/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java index b5d5fc60773226f097e723185f03b0a67d7c565a..4638635a94025121caa17d0ae01832eaab790ce7 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java @@ -26,7 +26,6 @@ import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.Gravity; import android.view.IWindow; @@ -38,6 +37,8 @@ import static android.view.WindowManager.LayoutParams.FILL_PARENT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import com.android.server.wm.utils.WmDisplayCutout; + /** * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery. * @@ -159,7 +160,7 @@ public class WindowFrameTests extends WindowTestsBase { // When mFrame extends past cf, the content insets are // the difference between mFrame and ContentFrame. Visible // and stable frames work the same way. - w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame,0, 0, 1000, 1000); assertRect(w.mContentInsets, 0, topContentInset, 0, bottomContentInset); assertRect(w.mVisibleInsets, 0, topVisibleInset, 0, bottomVisibleInset); @@ -174,7 +175,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT w.mRequestedWidth = 100; w.mRequestedHeight = 100; - w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 100, 100, 200, 200); assertRect(w.mContentInsets, 0, 0, 0, 0); // In this case the frames are shrunk to the window frame. @@ -195,7 +196,7 @@ public class WindowFrameTests extends WindowTestsBase { // Here the window has FILL_PARENT, FILL_PARENT // so we expect it to fill the entire available frame. - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 1000, 1000); // It can select various widths and heights within the bounds. @@ -203,14 +204,14 @@ public class WindowFrameTests extends WindowTestsBase { // and we use mRequestedWidth/mRequestedHeight w.mAttrs.width = 300; w.mAttrs.height = 300; - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); // Explicit width and height without requested width/height // gets us nothing. assertRect(w.mFrame, 0, 0, 0, 0); w.mRequestedWidth = 300; w.mRequestedHeight = 300; - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); // With requestedWidth/Height we can freely choose our size within the // parent bounds. assertRect(w.mFrame, 0, 0, 300, 300); @@ -223,14 +224,14 @@ public class WindowFrameTests extends WindowTestsBase { w.mRequestedWidth = -1; w.mAttrs.width = 100; w.mAttrs.height = 100; - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 100, 100); w.mAttrs.flags = 0; // But sizes too large will be clipped to the containing frame w.mRequestedWidth = 1200; w.mRequestedHeight = 1200; - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 1000, 1000); // Before they are clipped though windows will be shifted @@ -238,7 +239,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.y = 300; w.mRequestedWidth = 1000; w.mRequestedHeight = 1000; - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 1000, 1000); // If there is room to move around in the parent frame the window will be shifted according @@ -248,16 +249,16 @@ public class WindowFrameTests extends WindowTestsBase { w.mRequestedWidth = 300; w.mRequestedHeight = 300; w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP; - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 700, 0, 1000, 300); w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM; - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 700, 700, 1000, 1000); // Window specified x and y are interpreted as offsets in the opposite // direction of gravity w.mAttrs.x = 100; w.mAttrs.y = 100; - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 600, 600, 900, 900); } @@ -278,7 +279,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null, WmDisplayCutout.NO_CUTOUT, false); // For non fullscreen tasks the containing frame is based off the // task bounds not the parent frame. assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); @@ -290,7 +291,7 @@ public class WindowFrameTests extends WindowTestsBase { final int cfRight = logicalWidth / 2; final int cfBottom = logicalHeight / 2; final Rect cf = new Rect(0, 0, cfRight, cfBottom); - w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); int contentInsetRight = taskRight - cfRight; int contentInsetBottom = taskBottom - cfBottom; @@ -307,7 +308,7 @@ public class WindowFrameTests extends WindowTestsBase { final int insetRight = insetLeft + (taskRight - taskLeft); final int insetBottom = insetTop + (taskBottom - taskTop); task.mInsetBounds.set(insetLeft, insetTop, insetRight, insetBottom); - w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); contentInsetRight = insetRight - cfRight; contentInsetBottom = insetBottom - cfBottom; @@ -339,13 +340,13 @@ public class WindowFrameTests extends WindowTestsBase { final Rect policyCrop = new Rect(); - w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); w.calculatePolicyCrop(policyCrop); assertRect(policyCrop, 0, cf.top, logicalWidth, cf.bottom); dcf.setEmpty(); // Likewise with no decor frame we would get no crop - w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); w.calculatePolicyCrop(policyCrop); assertRect(policyCrop, 0, 0, logicalWidth, logicalHeight); @@ -358,7 +359,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.height = logicalHeight / 2; w.mRequestedWidth = logicalWidth / 2; w.mRequestedHeight = logicalHeight / 2; - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, DisplayCutout.NO_CUTOUT); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); w.calculatePolicyCrop(policyCrop); // Normally the crop is shrunk from the decor frame @@ -395,7 +396,7 @@ public class WindowFrameTests extends WindowTestsBase { final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */, pf /* contentFrame */, pf /* visibleFrame */, pf /* decorFrame */, - pf /* stableFrame */, null /* outsetFrame */, DisplayCutout.NO_CUTOUT); + pf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT, false); // For non fullscreen tasks the containing frame is based off the // task bounds not the parent frame. assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); @@ -414,7 +415,7 @@ public class WindowFrameTests extends WindowTestsBase { w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */, cf /* contentFrame */, cf /* visibleFrame */, pf /* decorFrame */, - cf /* stableFrame */, null /* outsetFrame */, DisplayCutout.NO_CUTOUT); + cf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT, false); assertEquals(cf, w.mFrame); assertEquals(cf, w.getContentFrameLw()); assertRect(w.mContentInsets, 0, 0, 0, 0); @@ -427,17 +428,17 @@ public class WindowFrameTests extends WindowTestsBase { WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; - final Rect pf = new Rect(0, 0, 1000, 1000); + final Rect pf = new Rect(0, 0, 1000, 2000); // Create a display cutout of size 50x50, aligned top-center - final DisplayCutout cutout = fromBoundingRect(500, 0, 550, 50) - .computeSafeInsets(pf.width(), pf.height()); + final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( + fromBoundingRect(500, 0, 550, 50), pf.width(), pf.height()); - w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, cutout); + w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, cutout, false); - assertEquals(w.mDisplayCutout.getSafeInsetTop(), 50); - assertEquals(w.mDisplayCutout.getSafeInsetBottom(), 0); - assertEquals(w.mDisplayCutout.getSafeInsetLeft(), 0); - assertEquals(w.mDisplayCutout.getSafeInsetRight(), 0); + assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetTop(), 50); + assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetBottom(), 0); + assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetLeft(), 0); + assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetRight(), 0); } private WindowStateWithTask createWindow(Task task, int width, int height) { 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 cdcb949b2a3c35aa10dd73cbffe20087729a4a08..56b7d9f40ec0b4d2f492b6c8de1d8fb892e99522 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/servicestests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f7addf6c77f90b697d0479d66b4f22ef5cce1f02 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java @@ -0,0 +1,157 @@ +/* + * 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 com.android.server.wm.utils; + + +import static android.view.DisplayCutout.NO_CUTOUT; +import static android.view.DisplayCutout.fromBoundingRect; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.util.Size; +import android.view.DisplayCutout; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; + +/** + * Tests for {@link WmDisplayCutout} + * + * Run with: atest WmDisplayCutoutTest + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class WmDisplayCutoutTest { + + private final DisplayCutout mCutoutTop = new DisplayCutout( + new Rect(0, 100, 0, 0), + Arrays.asList(new Rect(50, 0, 75, 100))); + + @Test + public void calculateRelativeTo_top() { + WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( + fromBoundingRect(0, 0, 100, 20), 200, 400) + .calculateRelativeTo(new Rect(5, 5, 95, 195)); + + assertEquals(new Rect(0, 15, 0, 0), cutout.getDisplayCutout().getSafeInsets()); + } + + @Test + public void calculateRelativeTo_left() { + WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( + fromBoundingRect(0, 0, 20, 100), 400, 200) + .calculateRelativeTo(new Rect(5, 5, 195, 95)); + + assertEquals(new Rect(15, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets()); + } + + @Test + public void calculateRelativeTo_bottom() { + WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( + fromBoundingRect(0, 180, 100, 200), 100, 200) + .calculateRelativeTo(new Rect(5, 5, 95, 195)); + + assertEquals(new Rect(0, 0, 0, 15), cutout.getDisplayCutout().getSafeInsets()); + } + + @Test + public void calculateRelativeTo_right() { + WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( + fromBoundingRect(180, 0, 200, 100), 200, 100) + .calculateRelativeTo(new Rect(5, 5, 195, 95)); + + assertEquals(new Rect(0, 0, 15, 0), cutout.getDisplayCutout().getSafeInsets()); + } + + @Test + public void calculateRelativeTo_bounds() { + WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( + fromBoundingRect(0, 0, 100, 20), 200, 400) + .calculateRelativeTo(new Rect(5, 10, 95, 180)); + + assertEquals(new Rect(-5, -10, 95, 10), cutout.getDisplayCutout().getBounds().getBounds()); + } + + @Test + public void computeSafeInsets_top() { + WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( + fromBoundingRect(0, 0, 100, 20), 200, 400); + + assertEquals(new Rect(0, 20, 0, 0), cutout.getDisplayCutout().getSafeInsets()); + } + + @Test + public void computeSafeInsets_left() { + WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( + fromBoundingRect(0, 0, 20, 100), 400, 200); + + assertEquals(new Rect(20, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets()); + } + + @Test + public void computeSafeInsets_bottom() { + WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( + fromBoundingRect(0, 180, 100, 200), 100, 200); + + assertEquals(new Rect(0, 0, 0, 20), cutout.getDisplayCutout().getSafeInsets()); + } + + @Test + public void computeSafeInsets_right() { + WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( + fromBoundingRect(180, 0, 200, 100), 200, 100); + + assertEquals(new Rect(0, 0, 20, 0), cutout.getDisplayCutout().getSafeInsets()); + } + + @Test + public void computeSafeInsets_bounds() { + DisplayCutout cutout = WmDisplayCutout.computeSafeInsets(mCutoutTop, 1000, + 2000).getDisplayCutout(); + + assertEquals(mCutoutTop.getBounds().getBounds(), + cutout.getBounds().getBounds()); + } + + @Test + public void test_equals() { + assertEquals(new WmDisplayCutout(NO_CUTOUT, null), new WmDisplayCutout(NO_CUTOUT, null)); + assertEquals(new WmDisplayCutout(mCutoutTop, new Size(1, 2)), + new WmDisplayCutout(mCutoutTop, new Size(1, 2))); + + assertNotEquals(new WmDisplayCutout(mCutoutTop, new Size(1, 2)), + new WmDisplayCutout(mCutoutTop, new Size(5, 6))); + assertNotEquals(new WmDisplayCutout(mCutoutTop, new Size(1, 2)), + new WmDisplayCutout(NO_CUTOUT, new Size(1, 2))); + } + + @Test + public void test_hashCode() { + assertEquals(new WmDisplayCutout(NO_CUTOUT, null).hashCode(), + new WmDisplayCutout(NO_CUTOUT, null).hashCode()); + assertEquals(new WmDisplayCutout(mCutoutTop, new Size(1, 2)).hashCode(), + new WmDisplayCutout(mCutoutTop, new Size(1, 2)).hashCode()); + } +} \ No newline at end of file diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml index fc459a0fc5b8fdbb23cfe9f84ae478cd80349128..4c7046676adb435655e8cf2b5a81abd74224a7ab 100644 --- a/services/tests/uiservicestests/AndroidManifest.xml +++ b/services/tests/uiservicestests/AndroidManifest.xml @@ -27,6 +27,7 @@ + diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index a92f7e7af5d86e9bb1c58848211df3800773a56e..cb64c9c5edd7c6e29d1770c2ef44df3ab50d7249 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -21,6 +21,7 @@ import static android.app.Notification.GROUP_ALERT_SUMMARY; import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_MIN; +import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; @@ -389,6 +390,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(r); verifyLights(); + assertTrue(r.isInterruptive()); } @Test @@ -400,6 +402,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verifyBeepLooped(); verifyNeverVibrate(); verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt()); + assertTrue(r.isInterruptive()); } @Test @@ -409,6 +412,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(r); verifyBeep(); + assertTrue(r.isInterruptive()); } @Test @@ -418,6 +422,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(r); verifyNeverBeep(); + assertFalse(r.isInterruptive()); } @Test @@ -429,6 +434,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verifyNeverBeep(); verifyNeverVibrate(); + assertFalse(r.isInterruptive()); } @Test @@ -440,6 +446,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verifyNeverBeep(); verifyNeverVibrate(); + assertFalse(r.isInterruptive()); } @Test @@ -455,6 +462,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(r); verifyBeepLooped(); verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt()); + assertTrue(r.isInterruptive()); } @Test @@ -482,6 +490,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(r); verifyNeverStopAudio(); + assertTrue(r.isInterruptive()); } @Test @@ -494,6 +503,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(s); verifyNeverStopAudio(); + assertTrue(r.isInterruptive()); + assertFalse(s.isInterruptive()); } @Test @@ -511,6 +522,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { // should not stop noise, since we no longer own it mService.buzzBeepBlinkLocked(s); // this no longer owns the stream verifyNeverStopAudio(); + assertTrue(other.isInterruptive()); } @Test @@ -535,11 +547,13 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { // set up internal state mService.buzzBeepBlinkLocked(r); + assertTrue(r.isInterruptive()); Mockito.reset(mRingtonePlayer); // quiet update should stop making noise mService.buzzBeepBlinkLocked(s); verifyStopAudio(); + assertFalse(s.isInterruptive()); } @Test @@ -550,11 +564,13 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { // set up internal state mService.buzzBeepBlinkLocked(r); + assertTrue(r.isInterruptive()); Mockito.reset(mRingtonePlayer); // stop making noise - this is a weird corner case, but quiet should override once mService.buzzBeepBlinkLocked(s); verifyStopAudio(); + assertFalse(s.isInterruptive()); } @Test @@ -570,6 +586,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verify(mService, times(1)).playInCallNotification(); verifyNeverBeep(); // doesn't play normal beep + assertTrue(r.isInterruptive()); } @Test @@ -587,6 +604,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(), eq(effect), (AudioAttributes) anyObject()); + assertTrue(r.isInterruptive()); } @Test @@ -603,6 +621,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verifyNeverVibrate(); verifyBeepLooped(); + assertTrue(r.isInterruptive()); } @Test @@ -621,6 +640,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { eq(FALLBACK_VIBRATION), (AudioAttributes) anyObject()); verify(mRingtonePlayer, never()).playAsync (anyObject(), anyObject(), anyBoolean(), anyObject()); + assertTrue(r.isInterruptive()); } @Test @@ -636,6 +656,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(r); verifyDelayedVibrateLooped(); + assertTrue(r.isInterruptive()); } @Test @@ -646,18 +667,20 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verifyNeverBeep(); verifyVibrate(); + assertTrue(r.isInterruptive()); } @Test - public void testInsistentVibrate() throws Exception { + public void testInsistentVibrate() { NotificationRecord r = getInsistentBuzzyNotification(); mService.buzzBeepBlinkLocked(r); verifyVibrateLooped(); + assertTrue(r.isInterruptive()); } @Test - public void testVibrateTwice() throws Exception { + public void testVibrateTwice() { NotificationRecord r = getBuzzyNotification(); // set up internal state @@ -668,6 +691,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { r.isUpdate = true; mService.buzzBeepBlinkLocked(r); verifyVibrate(); + assertTrue(r.isInterruptive()); } @Test @@ -677,6 +701,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(child); verifyNeverBeep(); + assertFalse(child.isInterruptive()); } @Test @@ -687,6 +712,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(summary); verifyBeepLooped(); + assertTrue(summary.isInterruptive()); } @Test @@ -696,6 +722,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(nonGroup); verifyBeepLooped(); + assertTrue(nonGroup.isInterruptive()); } @Test @@ -706,6 +733,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(summary); verifyNeverBeep(); + assertFalse(summary.isInterruptive()); } @Test @@ -715,6 +743,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(child); verifyBeepLooped(); + assertTrue(child.isInterruptive()); } @Test @@ -724,6 +753,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(nonGroup); verifyBeepLooped(); + assertTrue(nonGroup.isInterruptive()); } @Test @@ -733,6 +763,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(group); verifyBeepLooped(); + assertTrue(group.isInterruptive()); } @Test @@ -744,10 +775,12 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { // set up internal state mService.buzzBeepBlinkLocked(r); Mockito.reset(mVibrator); + assertTrue(r.isInterruptive()); // update should not beep mService.buzzBeepBlinkLocked(s); verifyNeverVibrate(); + assertFalse(s.isInterruptive()); } @Test @@ -759,6 +792,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(r); verifyNeverStopVibrate(); + assertTrue(r.isInterruptive()); } @Test @@ -771,6 +805,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(s); verifyNeverStopVibrate(); + assertTrue(r.isInterruptive()); + assertFalse(s.isInterruptive()); } @Test @@ -788,6 +824,9 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { // should not stop vibrate, since we no longer own it mService.buzzBeepBlinkLocked(s); // this no longer owns the stream verifyNeverStopVibrate(); + assertTrue(r.isInterruptive()); + assertTrue(other.isInterruptive()); + assertFalse(s.isInterruptive()); } @Test @@ -802,10 +841,11 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { // should not stop noise, since it does not own it mService.buzzBeepBlinkLocked(other); verifyNeverStopVibrate(); + assertFalse(other.isInterruptive()); } @Test - public void testQuietUpdateCancelsVibrate() throws Exception { + public void testQuietUpdateCancelsVibrate() { NotificationRecord r = getBuzzyNotification(); NotificationRecord s = getQuietNotification(); s.isUpdate = true; @@ -817,6 +857,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { // quiet update should stop making noise mService.buzzBeepBlinkLocked(s); verifyStopVibrate(); + assertTrue(r.isInterruptive()); + assertFalse(s.isInterruptive()); } @Test @@ -832,6 +874,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { // stop making noise - this is a weird corner case, but quiet should override once mService.buzzBeepBlinkLocked(s); verifyStopVibrate(); + assertTrue(r.isInterruptive()); + assertFalse(s.isInterruptive()); } @Test @@ -848,6 +892,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { // quiet update should stop making noise mService.buzzBeepBlinkLocked(s); verifyStopVibrate(); + assertTrue(r.isInterruptive()); + assertFalse(s.isInterruptive()); } @Test @@ -864,6 +910,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(r); verifyNeverBeep(); + assertFalse(r.isInterruptive()); } @Test @@ -874,6 +921,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(r); verifyNeverBeep(); + assertFalse(r.isInterruptive()); } @Test @@ -906,6 +954,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(r); verifyNeverBeep(); + assertFalse(r.isInterruptive()); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java index f4313b80c5202c84df2b987e4b75443bb739ca31..181fcebbb5369254dcb0acab6796231d417c7d47 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java @@ -70,6 +70,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { assertEquals(getSnoozeCriteria(key, i), ranking.getSnoozeCriteria()); assertEquals(getShowBadge(i), ranking.canShowBadge()); assertEquals(getUserSentiment(i), ranking.getUserSentiment()); + assertEquals(getHidden(i), ranking.isSuspended()); } } @@ -85,6 +86,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { Bundle showBadge = new Bundle(); int[] importance = new int[mKeys.length]; Bundle userSentiment = new Bundle(); + Bundle mHidden = new Bundle(); for (int i = 0; i < mKeys.length; i++) { String key = mKeys[i]; @@ -101,11 +103,12 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { snoozeCriteria.putParcelableArrayList(key, getSnoozeCriteria(key, i)); showBadge.putBoolean(key, getShowBadge(i)); userSentiment.putInt(key, getUserSentiment(i)); + mHidden.putBoolean(key, getHidden(i)); } NotificationRankingUpdate update = new NotificationRankingUpdate(mKeys, interceptedKeys.toArray(new String[0]), visibilityOverrides, suppressedVisualEffects, importance, explanation, overrideGroupKeys, - channels, overridePeople, snoozeCriteria, showBadge, userSentiment); + channels, overridePeople, snoozeCriteria, showBadge, userSentiment, mHidden); return update; } @@ -153,6 +156,10 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { return USER_SENTIMENT_NEUTRAL; } + private boolean getHidden(int index) { + return index % 2 == 0; + } + private ArrayList getPeople(String key, int index) { ArrayList people = new ArrayList<>(); for (int i = 0; i < index; i++) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 4fe54b9f15ef16fdfaf565dc42e9ac6610f4e72c..b82becd64f65527b9f3aa6a14c4b8d4893048e82 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -68,6 +68,7 @@ import android.app.Notification.MessagingStyle.Message; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationManager; +import android.app.usage.UsageStatsManagerInternal; import android.companion.ICompanionDeviceManager; import android.content.ComponentName; import android.content.Context; @@ -264,7 +265,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mPackageManager, mPackageManagerClient, mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, - mGroupHelper, mAm); + mGroupHelper, mAm, mock(UsageStatsManagerInternal.class)); } catch (SecurityException e) { if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) { throw e; @@ -2662,4 +2663,120 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(expected, actual); } + + @Test + public void testVisualDifference_diffTitle() { + Notification.Builder nb1 = new Notification.Builder(mContext, "") + .setContentTitle("foo"); + StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, + nb1.build(), new UserHandle(mUid), null, 0); + NotificationRecord r1 = + new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); + + Notification.Builder nb2 = new Notification.Builder(mContext, "") + .setContentTitle("bar"); + StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, + nb2.build(), new UserHandle(mUid), null, 0); + NotificationRecord r2 = + new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); + + assertTrue(mService.isVisuallyInterruptive(r1, r2)); + } + + @Test + public void testVisualDifference_diffText() { + Notification.Builder nb1 = new Notification.Builder(mContext, "") + .setContentText("foo"); + StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, + nb1.build(), new UserHandle(mUid), null, 0); + NotificationRecord r1 = + new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); + + Notification.Builder nb2 = new Notification.Builder(mContext, "") + .setContentText("bar"); + StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, + nb2.build(), new UserHandle(mUid), null, 0); + NotificationRecord r2 = + new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); + + assertTrue(mService.isVisuallyInterruptive(r1, r2)); + } + + @Test + public void testVisualDifference_diffProgress() { + Notification.Builder nb1 = new Notification.Builder(mContext, "") + .setProgress(100, 90, false); + StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, + nb1.build(), new UserHandle(mUid), null, 0); + NotificationRecord r1 = + new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); + + Notification.Builder nb2 = new Notification.Builder(mContext, "") + .setProgress(100, 100, false); + StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, + nb2.build(), new UserHandle(mUid), null, 0); + NotificationRecord r2 = + new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); + + assertTrue(mService.isVisuallyInterruptive(r1, r2)); + } + + @Test + public void testVisualDifference_diffProgressNotDone() { + Notification.Builder nb1 = new Notification.Builder(mContext, "") + .setProgress(100, 90, false); + StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, + nb1.build(), new UserHandle(mUid), null, 0); + NotificationRecord r1 = + new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); + + Notification.Builder nb2 = new Notification.Builder(mContext, "") + .setProgress(100, 91, false); + StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, + nb2.build(), new UserHandle(mUid), null, 0); + NotificationRecord r2 = + new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); + + assertFalse(mService.isVisuallyInterruptive(r1, r2)); + } + + @Test + public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() { + // post 2 notification from this package + final NotificationRecord notif1 = generateNotificationRecord( + mTestNotificationChannel, 1, null, true); + final NotificationRecord notif2 = generateNotificationRecord( + mTestNotificationChannel, 2, null, false); + mService.addNotification(notif1); + mService.addNotification(notif2); + + // on broadcast, hide the 2 notifications + mService.simulatePackageSuspendBroadcast(true, PKG); + ArgumentCaptor captorHide = ArgumentCaptor.forClass(List.class); + verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); + assertEquals(2, captorHide.getValue().size()); + + // on broadcast, unhide the 2 notifications + mService.simulatePackageSuspendBroadcast(false, PKG); + ArgumentCaptor captorUnhide = ArgumentCaptor.forClass(List.class); + verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); + assertEquals(2, captorUnhide.getValue().size()); + } + + @Test + public void testNoNotificationsHiddenOnSuspendedPackageBroadcast() { + // post 2 notification from this package + final NotificationRecord notif1 = generateNotificationRecord( + mTestNotificationChannel, 1, null, true); + final NotificationRecord notif2 = generateNotificationRecord( + mTestNotificationChannel, 2, null, false); + mService.addNotification(notif1); + mService.addNotification(notif2); + + // on broadcast, nothing is hidden since no notifications are of package "test_package" + mService.simulatePackageSuspendBroadcast(true, "test_package"); + ArgumentCaptor captor = ArgumentCaptor.forClass(List.class); + verify(mListeners, times(1)).notifyHiddenLocked(captor.capture()); + assertEquals(0, captor.getValue().size()); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java index 4bfb2362988e98148b49710bcf92b5b44a1d97f4..c4a688bb385d7b19aa1df246568dedd7f0a0e63d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java @@ -20,18 +20,27 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.Notification; +import android.app.Notification.Person; +import android.app.PendingIntent; +import android.app.RemoteInput; import android.content.Context; import android.content.pm.ApplicationInfo; +import android.graphics.Bitmap; import android.graphics.Color; +import android.graphics.drawable.Icon; +import android.net.Uri; import android.os.Build; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.widget.RemoteViews; import com.android.server.UiServiceTestCase; @@ -112,5 +121,272 @@ public class NotificationTest extends UiServiceTestCase { assertEquals(Color.RED, new Notification.CarExtender(before).getColor()); assertEquals("dismiss", new Notification.WearableExtender(before).getDismissalId()); } + + @Test + public void testStyleChangeVisiblyDifferent_noStyles() { + Notification.Builder n1 = new Notification.Builder(mContext, "test"); + Notification.Builder n2 = new Notification.Builder(mContext, "test"); + + assertFalse(Notification.areStyledNotificationsVisiblyDifferent(n1, n2)); + } + + @Test + public void testStyleChangeVisiblyDifferent_noStyleToStyle() { + Notification.Builder n1 = new Notification.Builder(mContext, "test"); + Notification.Builder n2 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.BigTextStyle()); + + assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2)); + } + + @Test + public void testStyleChangeVisiblyDifferent_styleToNoStyle() { + Notification.Builder n2 = new Notification.Builder(mContext, "test"); + Notification.Builder n1 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.BigTextStyle()); + + assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2)); + } + + @Test + public void testStyleChangeVisiblyDifferent_changeStyle() { + Notification.Builder n1 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.InboxStyle()); + Notification.Builder n2 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.BigTextStyle()); + + assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2)); + } + + @Test + public void testInboxTextChange() { + Notification.Builder nInbox1 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.InboxStyle().addLine("a").addLine("b")); + Notification.Builder nInbox2 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.InboxStyle().addLine("b").addLine("c")); + + assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nInbox1, nInbox2)); + } + + @Test + public void testBigTextTextChange() { + Notification.Builder nBigText1 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.BigTextStyle().bigText("something")); + Notification.Builder nBigText2 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.BigTextStyle().bigText("else")); + + assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nBigText1, nBigText2)); + } + + @Test + public void testBigPictureChange() { + Notification.Builder nBigPic1 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.BigPictureStyle().bigPicture(mock(Bitmap.class))); + Notification.Builder nBigPic2 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.BigPictureStyle().bigPicture(mock(Bitmap.class))); + + assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nBigPic1, nBigPic2)); + } + + @Test + public void testMessagingChange_text() { + Notification.Builder nM1 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("") + .addMessage(new Notification.MessagingStyle.Message( + "a", 100, mock(Notification.Person.class)))); + Notification.Builder nM2 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("") + .addMessage(new Notification.MessagingStyle.Message( + "a", 100, mock(Notification.Person.class))) + .addMessage(new Notification.MessagingStyle.Message( + "b", 100, mock(Notification.Person.class))) + ); + + assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2)); + } + + @Test + public void testMessagingChange_data() { + Notification.Builder nM1 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("") + .addMessage(new Notification.MessagingStyle.Message( + "a", 100, mock(Person.class)) + .setData("text", mock(Uri.class)))); + Notification.Builder nM2 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("") + .addMessage(new Notification.MessagingStyle.Message( + "a", 100, mock(Person.class)))); + + assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2)); + } + + @Test + public void testMessagingChange_sender() { + Person a = mock(Person.class); + when(a.getName()).thenReturn("A"); + Person b = mock(Person.class); + when(b.getName()).thenReturn("b"); + Notification.Builder nM1 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("") + .addMessage(new Notification.MessagingStyle.Message("a", 100, b))); + Notification.Builder nM2 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("") + .addMessage(new Notification.MessagingStyle.Message("a", 100, a))); + + assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2)); + } + + @Test + public void testMessagingChange_key() { + Person a = mock(Person.class); + when(a.getKey()).thenReturn("A"); + Person b = mock(Person.class); + when(b.getKey()).thenReturn("b"); + Notification.Builder nM1 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("") + .addMessage(new Notification.MessagingStyle.Message("a", 100, a))); + Notification.Builder nM2 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("") + .addMessage(new Notification.MessagingStyle.Message("a", 100, b))); + + assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2)); + } + + @Test + public void testMessagingChange_ignoreTimeChange() { + Notification.Builder nM1 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("") + .addMessage(new Notification.MessagingStyle.Message( + "a", 100, mock(Notification.Person.class)))); + Notification.Builder nM2 = new Notification.Builder(mContext, "test") + .setStyle(new Notification.MessagingStyle("") + .addMessage(new Notification.MessagingStyle.Message( + "a", 1000, mock(Notification.Person.class))) + ); + + assertFalse(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2)); + } + + @Test + public void testRemoteViews_nullChange() { + Notification.Builder n1 = new Notification.Builder(mContext, "test") + .setContent(mock(RemoteViews.class)); + Notification.Builder n2 = new Notification.Builder(mContext, "test"); + assertTrue(Notification.areRemoteViewsChanged(n1, n2)); + + n1 = new Notification.Builder(mContext, "test"); + n2 = new Notification.Builder(mContext, "test") + .setContent(mock(RemoteViews.class)); + assertTrue(Notification.areRemoteViewsChanged(n1, n2)); + + n1 = new Notification.Builder(mContext, "test") + .setCustomBigContentView(mock(RemoteViews.class)); + n2 = new Notification.Builder(mContext, "test"); + assertTrue(Notification.areRemoteViewsChanged(n1, n2)); + + n1 = new Notification.Builder(mContext, "test"); + n2 = new Notification.Builder(mContext, "test") + .setCustomBigContentView(mock(RemoteViews.class)); + assertTrue(Notification.areRemoteViewsChanged(n1, n2)); + + n1 = new Notification.Builder(mContext, "test"); + n2 = new Notification.Builder(mContext, "test"); + assertFalse(Notification.areRemoteViewsChanged(n1, n2)); + } + + @Test + public void testActionsDifferent_null() { + Notification n1 = new Notification.Builder(mContext, "test") + .build(); + Notification n2 = new Notification.Builder(mContext, "test") + .build(); + + assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); + } + + @Test + public void testActionsDifferentSame() { + PendingIntent intent = mock(PendingIntent.class); + Icon icon = mock(Icon.class); + + Notification n1 = new Notification.Builder(mContext, "test") + .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) + .build(); + Notification n2 = new Notification.Builder(mContext, "test") + .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) + .build(); + + assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); + } + + @Test + public void testActionsDifferentText() { + PendingIntent intent = mock(PendingIntent.class); + Icon icon = mock(Icon.class); + + Notification n1 = new Notification.Builder(mContext, "test") + .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) + .build(); + Notification n2 = new Notification.Builder(mContext, "test") + .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build()) + .build(); + + assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); + } + + @Test + public void testActionsDifferentNumber() { + PendingIntent intent = mock(PendingIntent.class); + Icon icon = mock(Icon.class); + + Notification n1 = new Notification.Builder(mContext, "test") + .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) + .build(); + Notification n2 = new Notification.Builder(mContext, "test") + .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) + .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build()) + .build(); + + assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); + } + + @Test + public void testActionsDifferentIntent() { + PendingIntent intent1 = mock(PendingIntent.class); + PendingIntent intent2 = mock(PendingIntent.class); + Icon icon = mock(Icon.class); + + Notification n1 = new Notification.Builder(mContext, "test") + .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent1).build()) + .build(); + Notification n2 = new Notification.Builder(mContext, "test") + .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build()) + .build(); + + assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); + } + + @Test + public void testActionsDifferentRemoteInputs() { + PendingIntent intent = mock(PendingIntent.class); + Icon icon = mock(Icon.class); + + Notification n1 = new Notification.Builder(mContext, "test") + .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent) + .addRemoteInput(new RemoteInput.Builder("a") + .setChoices(new CharSequence[] {"i", "m"}) + .build()) + .build()) + .build(); + Notification n2 = new Notification.Builder(mContext, "test") + .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent) + .addRemoteInput(new RemoteInput.Builder("a") + .setChoices(new CharSequence[] {"t", "m"}) + .build()) + .build()) + .build(); + + assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java index 354d2d5244fd256950a55b10419b59896e219c29..09d88fd8c87caafb18f2c526ee55a9788ab5d817 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java @@ -47,7 +47,9 @@ import android.content.ContentProvider; import android.content.Context; import android.content.IContentProvider; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.Signature; import android.content.res.Resources; import android.graphics.Color; import android.media.AudioAttributes; @@ -97,6 +99,8 @@ public class RankingHelperTest extends UiServiceTestCase { private static final UserHandle USER = UserHandle.of(0); private static final String UPDATED_PKG = "updatedPkg"; private static final int UID2 = 1111; + private static final String SYSTEM_PKG = "android"; + private static final int SYSTEM_UID= 1000; private static final UserHandle USER2 = UserHandle.of(10); private static final String TEST_CHANNEL_ID = "test_channel_id"; private static final String TEST_AUTHORITY = "test"; @@ -136,8 +140,15 @@ public class RankingHelperTest extends UiServiceTestCase { upgrade.targetSdkVersion = Build.VERSION_CODES.O; when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy); when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade); + when(mPm.getApplicationInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(upgrade); when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID); when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2); + when(mPm.getPackageUidAsUser(eq(SYSTEM_PKG), anyInt())).thenReturn(SYSTEM_UID); + PackageInfo info = mock(PackageInfo.class); + info.signatures = new Signature[] {mock(Signature.class)}; + when(mPm.getPackageInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(info); + when(mPm.getPackageInfoAsUser(eq(PKG), anyInt(), anyInt())) + .thenReturn(mock(PackageInfo.class)); when(mContext.getResources()).thenReturn( InstrumentationRegistry.getContext().getResources()); when(mContext.getContentResolver()).thenReturn( @@ -1627,4 +1638,52 @@ public class RankingHelperTest extends UiServiceTestCase { assertEquals(1, retrieved.getChannels().size()); compareChannels(a, findChannel(retrieved.getChannels(), a.getId())); } + + @Test + public void testAndroidPkgCanBypassDnd_creation() { + + NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); + test.setBypassDnd(true); + + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true); + + assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) + .canBypassDnd()); + } + + @Test + public void testNormalPkgCannotBypassDnd_creation() { + NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); + test.setBypassDnd(true); + + mHelper.createNotificationChannel(PKG, 1000, test, true); + + assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); + } + + @Test + public void testAndroidPkgCanBypassDnd_update() throws Exception { + NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true); + + NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); + update.setBypassDnd(true); + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true); + + assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) + .canBypassDnd()); + + // setup + 1st check + verify(mPm, times(2)).getPackageInfoAsUser(any(), anyInt(), anyInt()); + } + + @Test + public void testNormalPkgCannotBypassDnd_update() { + NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); + mHelper.createNotificationChannel(PKG, 1000, test, true); + NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); + update.setBypassDnd(true); + mHelper.createNotificationChannel(PKG, 1000, update, true); + assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); + } } 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 9008803c2c2f985725bd14d061c5aea2a4b96497..381e04c188b1c545ef7fac7b648feca68ba02e4a 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; @@ -48,9 +49,11 @@ import android.media.AudioSystem; import android.provider.Settings; import android.provider.Settings.Global; import android.service.notification.ZenModeConfig; +import android.service.notification.ZenModeConfig.ScheduleInfo; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.ArrayMap; import android.util.Xml; import com.android.internal.R; @@ -101,13 +104,13 @@ public class ZenModeHelperTest extends UiServiceTestCase { mConditionProviders)); } - private ByteArrayOutputStream writeXmlAndPurge(boolean forBackup) + private ByteArrayOutputStream writeXmlAndPurge(boolean forBackup, Integer version) throws Exception { XmlSerializer serializer = new FastXmlSerializer(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); serializer.startDocument(null, true); - mZenModeHelperSpy.writeXml(serializer, forBackup); + mZenModeHelperSpy.writeXml(serializer, forBackup, version); serializer.endDocument(); serializer.flush(); mZenModeHelperSpy.setConfig(new ZenModeConfig(), "writing xml"); @@ -159,6 +162,26 @@ public class ZenModeHelperTest extends UiServiceTestCase { AudioAttributes.USAGE_GAME); } + @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; @@ -179,9 +202,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 +251,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 +271,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); + } } } @@ -573,7 +605,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy(); - ByteArrayOutputStream baos = writeXmlAndPurge(false); + ByteArrayOutputStream baos = writeXmlAndPurge(false, null); XmlPullParser parser = Xml.newPullParser(); parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), null); @@ -583,6 +615,96 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertEquals(expected, mZenModeHelperSpy.mConfig); } + @Test + public void testReadXml() throws Exception { + setupZenConfig(); + + // automatic zen rule is enabled on upgrade so rules should not be overriden by default + ArrayMap enabledAutoRule = new ArrayMap<>(); + ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule(); + final ScheduleInfo weeknights = new ScheduleInfo(); + customRule.enabled = true; + customRule.name = "Custom Rule"; + customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights); + enabledAutoRule.put("customRule", customRule); + mZenModeHelperSpy.mConfig.automaticRules = enabledAutoRule; + + ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy(); + + // set previous version + ByteArrayOutputStream baos = writeXmlAndPurge(false, 5); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream( + new ByteArrayInputStream(baos.toByteArray())), null); + parser.nextTag(); + mZenModeHelperSpy.readXml(parser, false); + + assertTrue(mZenModeHelperSpy.mConfig.automaticRules.containsKey("customRule")); + setupZenConfigMaintained(); + } + + @Test + public void testReadXmlResetDefaultRules() throws Exception { + setupZenConfig(); + + // no enabled automatic zen rule, so rules should be overriden by default rules + mZenModeHelperSpy.mConfig.automaticRules = new ArrayMap<>(); + + // set previous version + ByteArrayOutputStream baos = writeXmlAndPurge(false, 5); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream( + new ByteArrayInputStream(baos.toByteArray())), null); + parser.nextTag(); + mZenModeHelperSpy.readXml(parser, false); + + // check default rules + ArrayMap rules = mZenModeHelperSpy.mConfig.automaticRules; + assertTrue(rules.size() != 0); + for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { + assertTrue(rules.containsKey(defaultId)); + } + + setupZenConfigMaintained(); + } + + + @Test + public void testReadXmlAllDisabledRulesResetDefaultRules() throws Exception { + setupZenConfig(); + + // all automatic zen rules are diabled on upgrade so rules should be overriden by default + // rules + ArrayMap enabledAutoRule = new ArrayMap<>(); + ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule(); + final ScheduleInfo weeknights = new ScheduleInfo(); + customRule.enabled = false; + customRule.name = "Custom Rule"; + customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights); + enabledAutoRule.put("customRule", customRule); + mZenModeHelperSpy.mConfig.automaticRules = enabledAutoRule; + + // set previous version + ByteArrayOutputStream baos = writeXmlAndPurge(false, 5); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream( + new ByteArrayInputStream(baos.toByteArray())), null); + parser.nextTag(); + mZenModeHelperSpy.readXml(parser, false); + + // check default rules + ArrayMap rules = mZenModeHelperSpy.mConfig.automaticRules; + assertTrue(rules.size() != 0); + for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) { + assertTrue(rules.containsKey(defaultId)); + } + assertFalse(rules.containsKey("customRule")); + + setupZenConfigMaintained(); + } + @Test public void testPolicyReadsSuppressedEffects() { mZenModeHelperSpy.mConfig.allowWhenScreenOff = true; @@ -592,4 +714,40 @@ public class ZenModeHelperTest extends UiServiceTestCase { NotificationManager.Policy policy = mZenModeHelperSpy.getNotificationPolicy(); assertEquals(SUPPRESSED_EFFECT_BADGE, policy.suppressedVisualEffects); } + + private void setupZenConfig() { + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mConfig.allowAlarms = false; + mZenModeHelperSpy.mConfig.allowMedia = false; + mZenModeHelperSpy.mConfig.allowSystem = false; + mZenModeHelperSpy.mConfig.allowReminders = true; + mZenModeHelperSpy.mConfig.allowCalls = true; + mZenModeHelperSpy.mConfig.allowMessages = true; + mZenModeHelperSpy.mConfig.allowEvents = true; + mZenModeHelperSpy.mConfig.allowRepeatCallers= true; + mZenModeHelperSpy.mConfig.allowWhenScreenOff = true; + mZenModeHelperSpy.mConfig.allowWhenScreenOn = true; + mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE; + mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule(); + mZenModeHelperSpy.mConfig.manualRule.zenMode = + Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a"); + mZenModeHelperSpy.mConfig.manualRule.enabled = true; + mZenModeHelperSpy.mConfig.manualRule.snoozing = true; + } + + private void setupZenConfigMaintained() { + // config is still the same as when it was setup (setupZenConfig) + assertFalse(mZenModeHelperSpy.mConfig.allowAlarms); + assertFalse(mZenModeHelperSpy.mConfig.allowMedia); + assertFalse(mZenModeHelperSpy.mConfig.allowSystem); + assertTrue(mZenModeHelperSpy.mConfig.allowReminders); + assertTrue(mZenModeHelperSpy.mConfig.allowCalls); + assertTrue(mZenModeHelperSpy.mConfig.allowMessages); + assertTrue(mZenModeHelperSpy.mConfig.allowEvents); + assertTrue(mZenModeHelperSpy.mConfig.allowRepeatCallers); + assertTrue(mZenModeHelperSpy.mConfig.allowWhenScreenOff); + assertTrue(mZenModeHelperSpy.mConfig.allowWhenScreenOn); + assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelperSpy.mConfig.suppressedVisualEffects); + } } 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 1052e8f377a790aa0682bf172b09b4bb753b6e1a..3c4e333b6be94e484cc52f150b99fd37c2836c0b 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 6fc300959144cc439b4c5bc0ab0064c316a8fee7..4f446a9afb98009f5c2c253eff087aabb32e7614 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/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java new file mode 100644 index 0000000000000000000000000000000000000000..9cd05933d8459e2f43deb7e99f03c5315aa15da3 --- /dev/null +++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java @@ -0,0 +1,464 @@ +/** + * 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 com.android.server.usage; + +import android.annotation.UserIdInt; +import android.app.PendingIntent; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Monitors and informs of any app time limits exceeded. It must be informed when an app + * enters the foreground and exits. Used by UsageStatsService. Manages multiple users. + * + * Test: atest FrameworksServicesTests:AppTimeLimitControllerTests + * Test: manual: frameworks/base/tests/UsageStatsTest + */ +public class AppTimeLimitController { + + private static final String TAG = "AppTimeLimitController"; + + private static final boolean DEBUG = false; + + /** Lock class for this object */ + private static class Lock {} + + /** Lock object for the data in this class. */ + private final Lock mLock = new Lock(); + + private final MyHandler mHandler; + + private OnLimitReachedListener mListener; + + @GuardedBy("mLock") + private final SparseArray mUsers = new SparseArray<>(); + + private static class UserData { + /** userId of the user */ + private @UserIdInt int userId; + + /** The app that is currently in the foreground */ + private String currentForegroundedPackage; + + /** The time when the current app came to the foreground */ + private long currentForegroundedTime; + + /** The last app that was in the background */ + private String lastBackgroundedPackage; + + /** Map from package name for quick lookup */ + private ArrayMap> packageMap = new ArrayMap<>(); + + /** Map of observerId to details of the time limit group */ + private SparseArray groups = new SparseArray<>(); + + UserData(@UserIdInt int userId) { + this.userId = userId; + } + } + + /** + * Listener interface for being informed when an app group's time limit is reached. + */ + public interface OnLimitReachedListener { + /** + * Time limit for a group, keyed by the observerId, has been reached. + * @param observerId The observerId of the group whose limit was reached + * @param userId The userId + * @param timeLimit The original time limit in milliseconds + * @param timeElapsed How much time was actually spent on apps in the group, in milliseconds + * @param callbackIntent The PendingIntent to send when the limit is reached + */ + public void onLimitReached(int observerId, @UserIdInt int userId, long timeLimit, + long timeElapsed, PendingIntent callbackIntent); + } + + static class TimeLimitGroup { + int requestingUid; + int observerId; + String[] packages; + long timeLimit; + long timeRequested; + long timeRemaining; + PendingIntent callbackIntent; + String currentPackage; + long timeCurrentPackageStarted; + int userId; + } + + class MyHandler extends Handler { + + static final int MSG_CHECK_TIMEOUT = 1; + static final int MSG_INFORM_LISTENER = 2; + + MyHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_CHECK_TIMEOUT: + checkTimeout((TimeLimitGroup) msg.obj); + break; + case MSG_INFORM_LISTENER: + informListener((TimeLimitGroup) msg.obj); + break; + default: + super.handleMessage(msg); + break; + } + } + } + + public AppTimeLimitController(OnLimitReachedListener listener, Looper looper) { + mHandler = new MyHandler(looper); + mListener = listener; + } + + /** Overrideable by a test */ + @VisibleForTesting + protected long getUptimeMillis() { + return SystemClock.uptimeMillis(); + } + + /** Returns an existing UserData object for the given userId, or creates one */ + UserData getOrCreateUserDataLocked(int userId) { + UserData userData = mUsers.get(userId); + if (userData == null) { + userData = new UserData(userId); + mUsers.put(userId, userData); + } + return userData; + } + + /** Clean up data if user is removed */ + public void onUserRemoved(int userId) { + synchronized (mLock) { + // TODO: Remove any inflight delayed messages + mUsers.remove(userId); + } + } + + /** + * Registers an observer with the given details. Existing observer with the same observerId + * is removed. + */ + public void addObserver(int requestingUid, int observerId, String[] packages, long timeLimit, + PendingIntent callbackIntent, @UserIdInt int userId) { + synchronized (mLock) { + UserData user = getOrCreateUserDataLocked(userId); + + removeObserverLocked(user, requestingUid, observerId); + + TimeLimitGroup group = new TimeLimitGroup(); + group.observerId = observerId; + group.callbackIntent = callbackIntent; + group.packages = packages; + group.timeLimit = timeLimit; + group.timeRemaining = group.timeLimit; + group.timeRequested = getUptimeMillis(); + group.requestingUid = requestingUid; + group.timeCurrentPackageStarted = -1L; + group.userId = userId; + + user.groups.append(observerId, group); + + addGroupToPackageMapLocked(user, packages, group); + + if (DEBUG) { + Slog.d(TAG, "addObserver " + packages + " for " + timeLimit); + } + // Handle the case where a target package is already in the foreground when observer + // is added. + if (user.currentForegroundedPackage != null && inPackageList(group.packages, + user.currentForegroundedPackage)) { + group.timeCurrentPackageStarted = group.timeRequested; + group.currentPackage = user.currentForegroundedPackage; + if (group.timeRemaining > 0) { + postCheckTimeoutLocked(group, group.timeRemaining); + } + } + } + } + + /** + * Remove a registered observer by observerId and calling uid. + * @param requestingUid The calling uid + * @param observerId The unique observer id for this user + * @param userId The user id of the observer + */ + public void removeObserver(int requestingUid, int observerId, @UserIdInt int userId) { + synchronized (mLock) { + UserData user = getOrCreateUserDataLocked(userId); + removeObserverLocked(user, requestingUid, observerId); + } + } + + @VisibleForTesting + TimeLimitGroup getObserverGroup(int observerId, int userId) { + synchronized (mLock) { + return getOrCreateUserDataLocked(userId).groups.get(observerId); + } + } + + private static boolean inPackageList(String[] packages, String packageName) { + return ArrayUtils.contains(packages, packageName); + } + + @GuardedBy("mLock") + private void removeObserverLocked(UserData user, int requestingUid, int observerId) { + TimeLimitGroup group = user.groups.get(observerId); + if (group != null && group.requestingUid == requestingUid) { + removeGroupFromPackageMapLocked(user, group); + user.groups.remove(observerId); + mHandler.removeMessages(MyHandler.MSG_CHECK_TIMEOUT, group); + } + } + + /** + * Called when an app has moved to the foreground. + * @param packageName The app that is foregrounded + * @param className The className of the activity + * @param userId The user + */ + public void moveToForeground(String packageName, String className, int userId) { + synchronized (mLock) { + UserData user = getOrCreateUserDataLocked(userId); + if (DEBUG) Slog.d(TAG, "Setting mCurrentForegroundedPackage to " + packageName); + // Note the current foreground package + user.currentForegroundedPackage = packageName; + user.currentForegroundedTime = getUptimeMillis(); + + // Check if the last package that was backgrounded is the same as this one + if (!TextUtils.equals(packageName, user.lastBackgroundedPackage)) { + // TODO: Move this logic up to usage stats to persist there. + incTotalLaunchesLocked(user, packageName); + } + + // Check if any of the groups need to watch for this package + maybeWatchForPackageLocked(user, packageName, user.currentForegroundedTime); + } + } + + /** + * Called when an app is sent to the background. + * + * @param packageName + * @param className + * @param userId + */ + public void moveToBackground(String packageName, String className, int userId) { + synchronized (mLock) { + UserData user = getOrCreateUserDataLocked(userId); + user.lastBackgroundedPackage = packageName; + if (!TextUtils.equals(user.currentForegroundedPackage, packageName)) { + Slog.w(TAG, "Eh? Last foregrounded package = " + user.currentForegroundedPackage + + " and now backgrounded = " + packageName); + return; + } + final long stopTime = getUptimeMillis(); + + // Add up the usage time to all groups that contain the package + ArrayList groups = user.packageMap.get(packageName); + if (groups != null) { + final int size = groups.size(); + for (int i = 0; i < size; i++) { + final TimeLimitGroup group = groups.get(i); + // Don't continue to send + if (group.timeRemaining <= 0) continue; + + final long startTime = Math.max(user.currentForegroundedTime, + group.timeRequested); + long diff = stopTime - startTime; + group.timeRemaining -= diff; + if (group.timeRemaining <= 0) { + if (DEBUG) Slog.d(TAG, "MTB informing group obs=" + group.observerId); + postInformListenerLocked(group); + } + // Reset indicators that observer was added when package was already fg + group.currentPackage = null; + group.timeCurrentPackageStarted = -1L; + mHandler.removeMessages(MyHandler.MSG_CHECK_TIMEOUT, group); + } + } + user.currentForegroundedPackage = null; + } + } + + private void postInformListenerLocked(TimeLimitGroup group) { + mHandler.sendMessage(mHandler.obtainMessage(MyHandler.MSG_INFORM_LISTENER, + group)); + } + + /** + * Inform the observer and unregister it, as the limit has been reached. + * @param group the observed group + */ + private void informListener(TimeLimitGroup group) { + if (mListener != null) { + mListener.onLimitReached(group.observerId, group.userId, group.timeLimit, + group.timeLimit - group.timeRemaining, group.callbackIntent); + } + // Unregister since the limit has been met and observer was informed. + synchronized (mLock) { + UserData user = getOrCreateUserDataLocked(group.userId); + removeObserverLocked(user, group.requestingUid, group.observerId); + } + } + + /** Check if any of the groups care about this package and set up delayed messages */ + @GuardedBy("mLock") + private void maybeWatchForPackageLocked(UserData user, String packageName, long uptimeMillis) { + ArrayList groups = user.packageMap.get(packageName); + if (groups == null) return; + + final int size = groups.size(); + for (int i = 0; i < size; i++) { + TimeLimitGroup group = groups.get(i); + if (group.timeRemaining > 0) { + group.timeCurrentPackageStarted = uptimeMillis; + group.currentPackage = packageName; + if (DEBUG) { + Slog.d(TAG, "Posting timeout for " + packageName + " for " + + group.timeRemaining + "ms"); + } + postCheckTimeoutLocked(group, group.timeRemaining); + } + } + } + + private void addGroupToPackageMapLocked(UserData user, String[] packages, + TimeLimitGroup group) { + for (int i = 0; i < packages.length; i++) { + ArrayList list = user.packageMap.get(packages[i]); + if (list == null) { + list = new ArrayList<>(); + user.packageMap.put(packages[i], list); + } + list.add(group); + } + } + + /** + * Remove the group reference from the package to group mapping, which is 1 to many. + * @param group The group to remove from the package map. + */ + private void removeGroupFromPackageMapLocked(UserData user, TimeLimitGroup group) { + final int mapSize = user.packageMap.size(); + for (int i = 0; i < mapSize; i++) { + ArrayList list = user.packageMap.valueAt(i); + list.remove(group); + } + } + + private void postCheckTimeoutLocked(TimeLimitGroup group, long timeout) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(MyHandler.MSG_CHECK_TIMEOUT, group), + timeout); + } + + /** + * See if the given group has reached the timeout if the current foreground app is included + * and it exceeds the time remaining. + * @param group the group of packages to check + */ + void checkTimeout(TimeLimitGroup group) { + // For each package in the group, check if any of the currently foregrounded apps are adding + // up to hit the limit and inform the observer + synchronized (mLock) { + UserData user = getOrCreateUserDataLocked(group.userId); + // This group doesn't exist anymore, nothing to see here. + if (user.groups.get(group.observerId) != group) return; + + if (DEBUG) Slog.d(TAG, "checkTimeout timeRemaining=" + group.timeRemaining); + + // Already reached the limit, no need to report again + if (group.timeRemaining <= 0) return; + + if (DEBUG) { + Slog.d(TAG, "checkTimeout foregroundedPackage=" + + user.currentForegroundedPackage); + } + + if (inPackageList(group.packages, user.currentForegroundedPackage)) { + if (DEBUG) { + Slog.d(TAG, "checkTimeout package in foreground=" + + user.currentForegroundedPackage); + } + if (group.timeCurrentPackageStarted < 0) { + Slog.w(TAG, "startTime was not set correctly for " + group); + } + final long timeInForeground = getUptimeMillis() - group.timeCurrentPackageStarted; + if (group.timeRemaining <= timeInForeground) { + if (DEBUG) Slog.d(TAG, "checkTimeout : Time limit reached"); + // Hit the limit, set timeRemaining to zero to avoid checking again + group.timeRemaining -= timeInForeground; + postInformListenerLocked(group); + // Reset + group.timeCurrentPackageStarted = -1L; + group.currentPackage = null; + } else { + if (DEBUG) Slog.d(TAG, "checkTimeout : Some more time remaining"); + postCheckTimeoutLocked(group, group.timeRemaining - timeInForeground); + } + } + } + } + + private void incTotalLaunchesLocked(UserData user, String packageName) { + // TODO: Inform UsageStatsService and aggregate the counter per app + } + + void dump(PrintWriter pw) { + synchronized (mLock) { + pw.println("\n App Time Limits"); + int nUsers = mUsers.size(); + for (int i = 0; i < nUsers; i++) { + UserData user = mUsers.valueAt(i); + pw.print(" User "); pw.println(user.userId); + int nGroups = user.groups.size(); + for (int j = 0; j < nGroups; j++) { + TimeLimitGroup group = user.groups.valueAt(j); + pw.print(" Group id="); pw.print(group.observerId); + pw.print(" timeLimit="); pw.print(group.timeLimit); + pw.print(" remaining="); pw.print(group.timeRemaining); + pw.print(" currentPackage="); pw.print(group.currentPackage); + pw.print(" timeCurrentPkgStarted="); pw.print(group.timeCurrentPackageStarted); + pw.print(" packages="); pw.println(Arrays.toString(group.packages)); + } + pw.println(); + pw.print(" currentForegroundedPackage="); + pw.println(user.currentForegroundedPackage); + pw.print(" lastBackgroundedPackage="); pw.println(user.lastBackgroundedPackage); + } + } + } +} diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 3c371e565220c6fb988598cf1cfa31265c325027..b144545c693ac5bd77b96f52b1febfed426e7a1f 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -20,6 +20,7 @@ import android.Manifest; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.IUidObserver; +import android.app.PendingIntent; import android.app.usage.AppStandbyInfo; import android.app.usage.ConfigurationStats; import android.app.usage.IUsageStatsManager; @@ -72,6 +73,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; /** * A service that collects, aggregates, and persists application usage data. @@ -117,6 +119,8 @@ public class UsageStatsService extends SystemService implements AppStandbyController mAppStandby; + AppTimeLimitController mAppTimeLimit; + private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener = new UsageStatsManagerInternal.AppIdleStateChangeListener() { @Override @@ -151,6 +155,20 @@ public class UsageStatsService extends SystemService implements mAppStandby = new AppStandbyController(getContext(), BackgroundThread.get().getLooper()); + mAppTimeLimit = new AppTimeLimitController( + (observerId, userId, timeLimit, timeElapsed, callbackIntent) -> { + Intent intent = new Intent(); + intent.putExtra(UsageStatsManager.EXTRA_OBSERVER_ID, observerId); + intent.putExtra(UsageStatsManager.EXTRA_TIME_LIMIT, timeLimit); + intent.putExtra(UsageStatsManager.EXTRA_TIME_USED, timeElapsed); + try { + callbackIntent.send(getContext(), 0, intent); + } catch (PendingIntent.CanceledException e) { + Slog.w(TAG, "Couldn't deliver callback: " + + callbackIntent); + } + }, mHandler.getLooper()); + mAppStandby.addListener(mStandbyChangeListener); File systemDataDir = new File(Environment.getDataDirectory(), "system"); mUsageStatsDir = new File(systemDataDir, "usagestats"); @@ -374,6 +392,16 @@ public class UsageStatsService extends SystemService implements service.reportEvent(event); mAppStandby.reportEvent(event, elapsedRealtime, userId); + switch (event.mEventType) { + case Event.MOVE_TO_FOREGROUND: + mAppTimeLimit.moveToForeground(event.getPackageName(), event.getClassName(), + userId); + break; + case Event.MOVE_TO_BACKGROUND: + mAppTimeLimit.moveToBackground(event.getPackageName(), event.getClassName(), + userId); + break; + } } } @@ -394,6 +422,7 @@ public class UsageStatsService extends SystemService implements Slog.i(TAG, "Removing user " + userId + " and all data."); mUserState.remove(userId); mAppStandby.onUserRemoved(userId); + mAppTimeLimit.onUserRemoved(userId); cleanUpRemovedUsersLocked(); } } @@ -549,6 +578,8 @@ public class UsageStatsService extends SystemService implements pw.println(); mAppStandby.dumpState(args, pw); } + + mAppTimeLimit.dump(pw); } } @@ -927,6 +958,60 @@ public class UsageStatsService extends SystemService implements mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } + + @Override + public void registerAppUsageObserver(int observerId, + String[] packages, long timeLimitMs, PendingIntent + callbackIntent, String callingPackage) { + if (!hasPermission(callingPackage)) { + throw new SecurityException("Caller doesn't have PACKAGE_USAGE_STATS permission"); + } + + if (packages == null || packages.length == 0) { + throw new IllegalArgumentException("Must specify at least one package"); + } + if (timeLimitMs <= 0) { + throw new IllegalArgumentException("Time limit must be > 0"); + } + if (callbackIntent == null) { + throw new NullPointerException("callbackIntent can't be null"); + } + final int callingUid = Binder.getCallingUid(); + final int userId = UserHandle.getUserId(callingUid); + final long token = Binder.clearCallingIdentity(); + try { + UsageStatsService.this.registerAppUsageObserver(callingUid, observerId, + packages, timeLimitMs, callbackIntent, userId); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void unregisterAppUsageObserver(int observerId, String callingPackage) { + if (!hasPermission(callingPackage)) { + throw new SecurityException("Caller doesn't have PACKAGE_USAGE_STATS permission"); + } + + final int callingUid = Binder.getCallingUid(); + final int userId = UserHandle.getUserId(callingUid); + final long token = Binder.clearCallingIdentity(); + try { + UsageStatsService.this.unregisterAppUsageObserver(callingUid, observerId, userId); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } + + void registerAppUsageObserver(int callingUid, int observerId, String[] packages, + long timeLimitMs, PendingIntent callbackIntent, int userId) { + mAppTimeLimit.addObserver(callingUid, observerId, packages, timeLimitMs, callbackIntent, + userId); + } + + void unregisterAppUsageObserver(int callingUid, int observerId, int userId) { + mAppTimeLimit.removeObserver(callingUid, observerId, userId); } /** @@ -989,6 +1074,25 @@ public class UsageStatsService extends SystemService implements mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } + @Override + public void reportInterruptiveNotification(String packageName, String channelId, + int userId) { + if (packageName == null || channelId == null) { + Slog.w(TAG, "Event reported without a package name or a channel ID"); + return; + } + + UsageEvents.Event event = new UsageEvents.Event(); + event.mPackage = packageName.intern(); + event.mNotificationChannelId = channelId.intern(); + + // This will later be converted to system time. + event.mTimeStamp = SystemClock.elapsedRealtime(); + + event.mEventType = Event.NOTIFICATION_INTERRUPTION; + mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); + } + @Override public void reportShortcutUsage(String packageName, String shortcutId, int userId) { if (packageName == null || shortcutId == null) { diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 836eb318e4dc6f0139b19793f7f7eb85d5d37974..d9742825ac705c34760921a2d72f2ab57140730c 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -759,6 +759,8 @@ class UserUsageStatsService { return "NOTIFICATION_SEEN"; case UsageEvents.Event.STANDBY_BUCKET_CHANGED: return "STANDBY_BUCKET_CHANGED"; + case UsageEvents.Event.NOTIFICATION_INTERRUPTION: + return "NOTIFICATION_INTERRUPTION"; default: return "UNKNOWN"; } diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java index cd3fdeefee13e083a5f55c7b6c4ae56f6530e24d..11609435205f2078d512db425f10b8c03f6d1928 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java @@ -15,36 +15,68 @@ */ package com.android.server.soundtrigger; + +import static android.Manifest.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE; +import static android.content.Context.BIND_AUTO_CREATE; +import static android.content.Context.BIND_FOREGROUND_SERVICE; +import static android.content.pm.PackageManager.GET_META_DATA; +import static android.content.pm.PackageManager.GET_SERVICES; +import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR; import static android.hardware.soundtrigger.SoundTrigger.STATUS_OK; +import static android.provider.Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY; +import static android.provider.Settings.Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.pm.PackageManager; -import android.Manifest; +import android.content.pm.ResolveInfo; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger; -import android.hardware.soundtrigger.SoundTrigger.SoundModel; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; +import android.hardware.soundtrigger.SoundTrigger.SoundModel; +import android.media.soundtrigger.ISoundTriggerDetectionService; +import android.media.soundtrigger.ISoundTriggerDetectionServiceClient; +import android.media.soundtrigger.SoundTriggerDetectionService; import android.media.soundtrigger.SoundTriggerManager; +import android.os.Binder; import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; import android.os.Parcel; import android.os.ParcelUuid; import android.os.PowerManager; import android.os.RemoteException; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Slog; -import com.android.server.SystemService; +import com.android.internal.annotations.GuardedBy; import com.android.internal.app.ISoundTriggerService; +import com.android.internal.util.DumpUtils; +import com.android.internal.util.Preconditions; +import com.android.server.SystemService; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.TreeMap; import java.util.UUID; +import java.util.concurrent.TimeUnit; /** * A single SystemService to manage all sound/voice-based sound models on the DSP. @@ -67,9 +99,13 @@ public class SoundTriggerService extends SystemService { private SoundTriggerHelper mSoundTriggerHelper; private final TreeMap mLoadedModels; private Object mCallbacksLock; - private final TreeMap mIntentCallbacks; + private final TreeMap mCallbacks; private PowerManager.WakeLock mWakelock; + /** Number of ops run by the {@link RemoteSoundTriggerDetectionService} per package name */ + @GuardedBy("mLock") + private final ArrayMap mNumOpsPerPackage = new ArrayMap<>(); + public SoundTriggerService(Context context) { super(context); mContext = context; @@ -77,7 +113,7 @@ public class SoundTriggerService extends SystemService { mLocalSoundTriggerService = new LocalSoundTriggerService(context); mLoadedModels = new TreeMap(); mCallbacksLock = new Object(); - mIntentCallbacks = new TreeMap(); + mCallbacks = new TreeMap<>(); mLock = new Object(); } @@ -214,7 +250,7 @@ public class SoundTriggerService extends SystemService { if (oldModel != null && !oldModel.equals(soundModel)) { mSoundTriggerHelper.unloadGenericSoundModel(soundModel.uuid); synchronized (mCallbacksLock) { - mIntentCallbacks.remove(soundModel.uuid); + mCallbacks.remove(soundModel.uuid); } } mLoadedModels.put(soundModel.uuid, soundModel); @@ -245,7 +281,7 @@ public class SoundTriggerService extends SystemService { if (oldModel != null && !oldModel.equals(soundModel)) { mSoundTriggerHelper.unloadKeyphraseSoundModel(soundModel.keyphrases[0].id); synchronized (mCallbacksLock) { - mIntentCallbacks.remove(soundModel.uuid); + mCallbacks.remove(soundModel.uuid); } } mLoadedModels.put(soundModel.uuid, soundModel); @@ -253,9 +289,29 @@ public class SoundTriggerService extends SystemService { return STATUS_OK; } + @Override + public int startRecognitionForService(ParcelUuid soundModelId, Bundle params, + ComponentName detectionService, SoundTrigger.RecognitionConfig config) { + Preconditions.checkNotNull(soundModelId); + Preconditions.checkNotNull(detectionService); + Preconditions.checkNotNull(config); + + return startRecognitionForInt(soundModelId, + new RemoteSoundTriggerDetectionService(soundModelId.getUuid(), + params, detectionService, Binder.getCallingUserHandle(), config), config); + + } + @Override public int startRecognitionForIntent(ParcelUuid soundModelId, PendingIntent callbackIntent, SoundTrigger.RecognitionConfig config) { + return startRecognitionForInt(soundModelId, + new LocalSoundTriggerRecognitionStatusIntentCallback(soundModelId.getUuid(), + callbackIntent, config), config); + } + + private int startRecognitionForInt(ParcelUuid soundModelId, + IRecognitionStatusCallback callback, SoundTrigger.RecognitionConfig config) { enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER); if (!isInitialized()) return STATUS_ERROR; if (DEBUG) { @@ -268,27 +324,25 @@ public class SoundTriggerService extends SystemService { Slog.e(TAG, soundModelId + " is not loaded"); return STATUS_ERROR; } - LocalSoundTriggerRecognitionStatusCallback callback = null; + IRecognitionStatusCallback existingCallback = null; synchronized (mCallbacksLock) { - callback = mIntentCallbacks.get(soundModelId.getUuid()); + existingCallback = mCallbacks.get(soundModelId.getUuid()); } - if (callback != null) { + if (existingCallback != null) { Slog.e(TAG, soundModelId + " is already running"); return STATUS_ERROR; } - callback = new LocalSoundTriggerRecognitionStatusCallback(soundModelId.getUuid(), - callbackIntent, config); int ret; switch (soundModel.type) { case SoundModel.TYPE_KEYPHRASE: { KeyphraseSoundModel keyphraseSoundModel = (KeyphraseSoundModel) soundModel; ret = mSoundTriggerHelper.startKeyphraseRecognition( - keyphraseSoundModel.keyphrases[0].id, keyphraseSoundModel, callback, - config); + keyphraseSoundModel.keyphrases[0].id, keyphraseSoundModel, callback, + config); } break; case SoundModel.TYPE_GENERIC_SOUND: ret = mSoundTriggerHelper.startGenericRecognition(soundModel.uuid, - (GenericSoundModel) soundModel, callback, config); + (GenericSoundModel) soundModel, callback, config); break; default: Slog.e(TAG, "Unknown model type"); @@ -300,7 +354,7 @@ public class SoundTriggerService extends SystemService { return ret; } synchronized (mCallbacksLock) { - mIntentCallbacks.put(soundModelId.getUuid(), callback); + mCallbacks.put(soundModelId.getUuid(), callback); } } return STATUS_OK; @@ -320,9 +374,9 @@ public class SoundTriggerService extends SystemService { Slog.e(TAG, soundModelId + " is not loaded"); return STATUS_ERROR; } - LocalSoundTriggerRecognitionStatusCallback callback = null; + IRecognitionStatusCallback callback = null; synchronized (mCallbacksLock) { - callback = mIntentCallbacks.get(soundModelId.getUuid()); + callback = mCallbacks.get(soundModelId.getUuid()); } if (callback == null) { Slog.e(TAG, soundModelId + " is not running"); @@ -347,7 +401,7 @@ public class SoundTriggerService extends SystemService { return ret; } synchronized (mCallbacksLock) { - mIntentCallbacks.remove(soundModelId.getUuid()); + mCallbacks.remove(soundModelId.getUuid()); } } return STATUS_OK; @@ -394,8 +448,7 @@ public class SoundTriggerService extends SystemService { enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER); if (!isInitialized()) return false; synchronized (mCallbacksLock) { - LocalSoundTriggerRecognitionStatusCallback callback = - mIntentCallbacks.get(parcelUuid.getUuid()); + IRecognitionStatusCallback callback = mCallbacks.get(parcelUuid.getUuid()); if (callback == null) { return false; } @@ -404,13 +457,13 @@ public class SoundTriggerService extends SystemService { } } - private final class LocalSoundTriggerRecognitionStatusCallback + private final class LocalSoundTriggerRecognitionStatusIntentCallback extends IRecognitionStatusCallback.Stub { private UUID mUuid; private PendingIntent mCallbackIntent; private RecognitionConfig mRecognitionConfig; - public LocalSoundTriggerRecognitionStatusCallback(UUID modelUuid, + public LocalSoundTriggerRecognitionStatusIntentCallback(UUID modelUuid, PendingIntent callbackIntent, RecognitionConfig config) { mUuid = modelUuid; @@ -528,7 +581,7 @@ public class SoundTriggerService extends SystemService { private void removeCallback(boolean releaseWakeLock) { mCallbackIntent = null; synchronized (mCallbacksLock) { - mIntentCallbacks.remove(mUuid); + mCallbacks.remove(mUuid); if (releaseWakeLock) { mWakelock.release(); } @@ -536,6 +589,478 @@ public class SoundTriggerService extends SystemService { } } + /** + * Counts the number of operations added in the last 24 hours. + */ + private static class NumOps { + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private int[] mNumOps = new int[24]; + @GuardedBy("mLock") + private long mLastOpsHourSinceBoot; + + /** + * Clear buckets of new hours that have elapsed since last operation. + * + *

    I.e. when the last operation was triggered at 1:40 and the current operation was + * triggered at 4:03, the buckets "2, 3, and 4" are cleared. + * + * @param currentTime Current elapsed time since boot in ns + */ + void clearOldOps(long currentTime) { + synchronized (mLock) { + long numHoursSinceBoot = TimeUnit.HOURS.convert(currentTime, TimeUnit.NANOSECONDS); + + // Clear buckets of new hours that have elapsed since last operation + // I.e. when the last operation was triggered at 1:40 and the current + // operation was triggered at 4:03, the bucket "2, 3, and 4" is cleared + if (mLastOpsHourSinceBoot != 0) { + for (long hour = mLastOpsHourSinceBoot + 1; hour <= numHoursSinceBoot; hour++) { + mNumOps[(int) (hour % 24)] = 0; + } + } + } + } + + /** + * Add a new operation. + * + * @param currentTime Current elapsed time since boot in ns + */ + void addOp(long currentTime) { + synchronized (mLock) { + long numHoursSinceBoot = TimeUnit.HOURS.convert(currentTime, TimeUnit.NANOSECONDS); + + mNumOps[(int) (numHoursSinceBoot % 24)]++; + mLastOpsHourSinceBoot = numHoursSinceBoot; + } + } + + /** + * Get the total operations added in the last 24 hours. + * + * @return The total number of operations added in the last 24 hours + */ + int getOpsAdded() { + synchronized (mLock) { + int totalOperationsInLastDay = 0; + for (int i = 0; i < 24; i++) { + totalOperationsInLastDay += mNumOps[i]; + } + + return totalOperationsInLastDay; + } + } + } + + private interface Operation { + void run(int opId, ISoundTriggerDetectionService service) throws RemoteException; + } + + /** + * Local end for a {@link SoundTriggerDetectionService}. Operations are queued up and executed + * when the service connects. + * + *

    If operations take too long they are forcefully aborted. + * + *

    This also limits the amount of operations in 24 hours. + */ + private class RemoteSoundTriggerDetectionService + extends IRecognitionStatusCallback.Stub implements ServiceConnection { + private static final int MSG_STOP_ALL_PENDING_OPERATIONS = 1; + + private final Object mRemoteServiceLock = new Object(); + + /** UUID of the model the service is started for */ + private final @NonNull ParcelUuid mPuuid; + /** Params passed into the start method for the service */ + private final @Nullable Bundle mParams; + /** Component name passed when starting the service */ + private final @NonNull ComponentName mServiceName; + /** User that started the service */ + private final @NonNull UserHandle mUser; + /** Configuration of the recognition the service is handling */ + private final @NonNull RecognitionConfig mRecognitionConfig; + /** Wake lock keeping the remote service alive */ + private final @NonNull PowerManager.WakeLock mRemoteServiceWakeLock; + + private final @NonNull Handler mHandler; + + /** Callbacks that are called by the service */ + private final @NonNull ISoundTriggerDetectionServiceClient mClient; + + /** Operations that are pending because the service is not yet connected */ + @GuardedBy("mRemoteServiceLock") + private final ArrayList mPendingOps = new ArrayList<>(); + /** Operations that have been send to the service but have no yet finished */ + @GuardedBy("mRemoteServiceLock") + private final ArraySet mRunningOpIds = new ArraySet<>(); + /** The number of operations executed in each of the last 24 hours */ + private final NumOps mNumOps; + + /** The service binder if connected */ + @GuardedBy("mRemoteServiceLock") + private @Nullable ISoundTriggerDetectionService mService; + /** Whether the service has been bound */ + @GuardedBy("mRemoteServiceLock") + private boolean mIsBound; + /** Whether the service has been destroyed */ + @GuardedBy("mRemoteServiceLock") + private boolean mIsDestroyed; + /** + * Set once a final op is scheduled. No further ops can be added and the service is + * destroyed once the op finishes. + */ + @GuardedBy("mRemoteServiceLock") + private boolean mDestroyOnceRunningOpsDone; + + /** Total number of operations performed by this service */ + @GuardedBy("mRemoteServiceLock") + private int mNumTotalOpsPerformed; + + /** + * Create a new remote sound trigger detection service. This only binds to the service when + * operations are in flight. Each operation has a certain time it can run. Once no + * operations are allowed to run anymore, {@link #stopAllPendingOperations() all operations + * are aborted and stopped} and the service is disconnected. + * + * @param modelUuid The UUID of the model the recognition is for + * @param params The params passed to each method of the service + * @param serviceName The component name of the service + * @param user The user of the service + * @param config The configuration of the recognition + */ + public RemoteSoundTriggerDetectionService(@NonNull UUID modelUuid, + @Nullable Bundle params, @NonNull ComponentName serviceName, @NonNull UserHandle user, + @NonNull RecognitionConfig config) { + mPuuid = new ParcelUuid(modelUuid); + mParams = params; + mServiceName = serviceName; + mUser = user; + mRecognitionConfig = config; + mHandler = new Handler(Looper.getMainLooper()); + + PowerManager pm = ((PowerManager) mContext.getSystemService(Context.POWER_SERVICE)); + mRemoteServiceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + "RemoteSoundTriggerDetectionService " + mServiceName.getPackageName() + ":" + + mServiceName.getClassName()); + + synchronized (mLock) { + NumOps numOps = mNumOpsPerPackage.get(mServiceName.getPackageName()); + if (numOps == null) { + numOps = new NumOps(); + mNumOpsPerPackage.put(mServiceName.getPackageName(), numOps); + } + mNumOps = numOps; + } + + mClient = new ISoundTriggerDetectionServiceClient.Stub() { + @Override + public void onOpFinished(int opId) { + long token = Binder.clearCallingIdentity(); + try { + synchronized (mRemoteServiceLock) { + mRunningOpIds.remove(opId); + + if (mRunningOpIds.isEmpty() && mPendingOps.isEmpty()) { + if (mDestroyOnceRunningOpsDone) { + destroy(); + } else { + disconnectLocked(); + } + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + }; + } + + @Override + public boolean pingBinder() { + return !(mIsDestroyed || mDestroyOnceRunningOpsDone); + } + + /** + * Disconnect from the service, but allow to re-connect when new operations are triggered. + */ + private void disconnectLocked() { + if (mService != null) { + try { + mService.removeClient(mPuuid); + } catch (Exception e) { + Slog.e(TAG, mPuuid + ": Cannot remove client", e); + } + + mService = null; + } + + if (mIsBound) { + mContext.unbindService(RemoteSoundTriggerDetectionService.this); + mIsBound = false; + + synchronized (mCallbacksLock) { + mRemoteServiceWakeLock.release(); + } + } + } + + /** + * Disconnect, do not allow to reconnect to the service. All further operations will be + * dropped. + */ + private void destroy() { + if (DEBUG) Slog.v(TAG, mPuuid + ": destroy"); + + synchronized (mRemoteServiceLock) { + disconnectLocked(); + + mIsDestroyed = true; + } + + // The callback is removed before the flag is set + if (!mDestroyOnceRunningOpsDone) { + synchronized (mCallbacksLock) { + mCallbacks.remove(mPuuid.getUuid()); + } + } + } + + /** + * Stop all pending operations and then disconnect for the service. + */ + private void stopAllPendingOperations() { + synchronized (mRemoteServiceLock) { + if (mIsDestroyed) { + return; + } + + if (mService != null) { + int numOps = mRunningOpIds.size(); + for (int i = 0; i < numOps; i++) { + try { + mService.onStopOperation(mPuuid, mRunningOpIds.valueAt(i)); + } catch (Exception e) { + Slog.e(TAG, mPuuid + ": Could not stop operation " + + mRunningOpIds.valueAt(i), e); + } + } + + mRunningOpIds.clear(); + } + + disconnectLocked(); + } + } + + /** + * Verify that the service has the expected properties and then bind to the service + */ + private void bind() { + long token = Binder.clearCallingIdentity(); + try { + Intent i = new Intent(); + i.setComponent(mServiceName); + + ResolveInfo ri = mContext.getPackageManager().resolveServiceAsUser(i, + GET_SERVICES | GET_META_DATA | MATCH_DEBUG_TRIAGED_MISSING, + mUser.getIdentifier()); + + if (ri == null) { + Slog.w(TAG, mPuuid + ": " + mServiceName + " not found"); + return; + } + + if (!BIND_SOUND_TRIGGER_DETECTION_SERVICE + .equals(ri.serviceInfo.permission)) { + Slog.w(TAG, mPuuid + ": " + mServiceName + " does not require " + + BIND_SOUND_TRIGGER_DETECTION_SERVICE); + return; + } + + mIsBound = mContext.bindServiceAsUser(i, this, + BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE, mUser); + + if (mIsBound) { + mRemoteServiceWakeLock.acquire(); + } else { + Slog.w(TAG, mPuuid + ": Could not bind to " + mServiceName); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** + * Run an operation (i.e. send it do the service). If the service is not connected, this + * binds the service and then runs the operation once connected. + * + * @param op The operation to run + */ + private void runOrAddOperation(Operation op) { + synchronized (mRemoteServiceLock) { + if (mIsDestroyed || mDestroyOnceRunningOpsDone) { + return; + } + + if (mService == null) { + mPendingOps.add(op); + + if (!mIsBound) { + bind(); + } + } else { + long currentTime = System.nanoTime(); + mNumOps.clearOldOps(currentTime); + + // Drop operation if too many were executed in the last 24 hours. + int opsAllowed = Settings.Global.getInt(mContext.getContentResolver(), + MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY, + Integer.MAX_VALUE); + + int opsAdded = mNumOps.getOpsAdded(); + if (mNumOps.getOpsAdded() >= opsAllowed) { + if (DEBUG || opsAllowed + 10 > opsAdded) { + Slog.w(TAG, mPuuid + ": Dropped operation as too many operations were " + + "run in last 24 hours"); + } + return; + } + + mNumOps.addOp(currentTime); + + // Find a free opID + int opId = mNumTotalOpsPerformed; + do { + mNumTotalOpsPerformed++; + } while (mRunningOpIds.contains(opId)); + + // Run OP + try { + if (DEBUG) Slog.v(TAG, mPuuid + ": runOp " + opId); + + op.run(opId, mService); + mRunningOpIds.add(opId); + } catch (Exception e) { + Slog.e(TAG, mPuuid + ": Could not run operation " + opId, e); + } + + // Unbind from service if no operations are left (i.e. if the operation failed) + if (mPendingOps.isEmpty() && mRunningOpIds.isEmpty()) { + if (mDestroyOnceRunningOpsDone) { + destroy(); + } else { + disconnectLocked(); + } + } else { + mHandler.removeMessages(MSG_STOP_ALL_PENDING_OPERATIONS); + mHandler.sendMessageDelayed(obtainMessage( + RemoteSoundTriggerDetectionService::stopAllPendingOperations, this) + .setWhat(MSG_STOP_ALL_PENDING_OPERATIONS), + Settings.Global.getLong(mContext.getContentResolver(), + SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT, + Long.MAX_VALUE)); + } + } + } + } + + @Override + public void onKeyphraseDetected(SoundTrigger.KeyphraseRecognitionEvent event) { + Slog.w(TAG, mPuuid + "->" + mServiceName + ": IGNORED onKeyphraseDetected(" + event + + ")"); + } + + @Override + public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) { + if (DEBUG) Slog.v(TAG, mPuuid + ": Generic sound trigger event: " + event); + + runOrAddOperation((opId, service) -> { + if (!mRecognitionConfig.allowMultipleTriggers) { + synchronized (mCallbacksLock) { + mCallbacks.remove(mPuuid.getUuid()); + } + mDestroyOnceRunningOpsDone = true; + } + + service.onGenericRecognitionEvent(mPuuid, opId, event); + }); + } + + @Override + public void onError(int status) { + if (DEBUG) Slog.v(TAG, mPuuid + ": onError: " + status); + + runOrAddOperation((opId, service) -> { + synchronized (mCallbacksLock) { + mCallbacks.remove(mPuuid.getUuid()); + } + mDestroyOnceRunningOpsDone = true; + + service.onError(mPuuid, opId, status); + }); + } + + @Override + public void onRecognitionPaused() { + Slog.i(TAG, mPuuid + "->" + mServiceName + ": IGNORED onRecognitionPaused"); + } + + @Override + public void onRecognitionResumed() { + Slog.i(TAG, mPuuid + "->" + mServiceName + ": IGNORED onRecognitionResumed"); + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (DEBUG) Slog.v(TAG, mPuuid + ": onServiceConnected(" + service + ")"); + + synchronized (mRemoteServiceLock) { + mService = ISoundTriggerDetectionService.Stub.asInterface(service); + + try { + mService.setClient(mPuuid, mParams, mClient); + } catch (Exception e) { + Slog.e(TAG, mPuuid + ": Could not init " + mServiceName, e); + return; + } + + while (!mPendingOps.isEmpty()) { + runOrAddOperation(mPendingOps.remove(0)); + } + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + if (DEBUG) Slog.v(TAG, mPuuid + ": onServiceDisconnected"); + + synchronized (mRemoteServiceLock) { + mService = null; + } + } + + @Override + public void onBindingDied(ComponentName name) { + if (DEBUG) Slog.v(TAG, mPuuid + ": onBindingDied"); + + synchronized (mRemoteServiceLock) { + destroy(); + } + } + + @Override + public void onNullBinding(ComponentName name) { + Slog.w(TAG, name + " for model " + mPuuid + " returned a null binding"); + + synchronized (mRemoteServiceLock) { + disconnectLocked(); + } + } + } + private void grabWakeLock() { synchronized (mCallbacksLock) { if (mWakelock == null) { diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index 85378bf622716d055b83186a2609079cb6f9de9e..d49515f098fd791916b75ea39641f993aaed72a8 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -3212,8 +3212,8 @@ public final class Telephony { values.put(RIL_VOICE_RADIO_TECHNOLOGY, state.getRilVoiceRadioTechnology()); values.put(RIL_DATA_RADIO_TECHNOLOGY, state.getRilDataRadioTechnology()); values.put(CSS_INDICATOR, state.getCssIndicator()); - values.put(NETWORK_ID, state.getNetworkId()); - values.put(SYSTEM_ID, state.getSystemId()); + values.put(NETWORK_ID, state.getCdmaNetworkId()); + values.put(SYSTEM_ID, state.getCdmaSystemId()); values.put(CDMA_ROAMING_INDICATOR, state.getCdmaRoamingIndicator()); values.put(CDMA_DEFAULT_ROAMING_INDICATOR, state.getCdmaDefaultRoamingIndicator()); values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex()); @@ -3343,13 +3343,13 @@ public final class Telephony { public static final String CSS_INDICATOR = "css_indicator"; /** - * This is the same as {@link ServiceState#getNetworkId()}. + * This is the same as {@link ServiceState#getCdmaNetworkId()}. * @hide */ public static final String NETWORK_ID = "network_id"; /** - * This is the same as {@link ServiceState#getSystemId()}. + * This is the same as {@link ServiceState#getCdmaSystemId()}. * @hide */ public static final String SYSTEM_ID = "system_id"; @@ -3427,7 +3427,7 @@ public final class Telephony { * on the given subscriptionId *

    * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the - * carrier identity {@link TelephonyManager#getAndroidCarrierIdForSubscription()} + * carrier identity {@link TelephonyManager#getSimCarrierId()} * while your app is running. You can also use a {@link JobService} to ensure your app * is notified of changes to the {@link Uri} even when it is not running. * Note, however, that using a {@link JobService} does not guarantee timely delivery of @@ -3443,14 +3443,14 @@ public final class Telephony { /** * A user facing carrier name. - * @see TelephonyManager#getAndroidCarrierNameForSubscription() + * @see TelephonyManager#getSimCarrierIdName() *

    Type: TEXT

    */ public static final String CARRIER_NAME = "carrier_name"; /** * A unique carrier id - * @see TelephonyManager#getAndroidCarrierIdForSubscription() + * @see TelephonyManager#getSimCarrierId() *

    Type: INTEGER

    */ public static final String CARRIER_ID = "carrier_id"; diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..5d2c225f28eca297b1cbbf5bb1978d56086e2052 --- /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. + * + *

    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. + * + *

    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/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index c3cb315e36ae851a64e14c2224e7212d3882f29f..0c646ff8c69e503a2483cf647c5c494fb6de08fc 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1285,12 +1285,37 @@ public class CarrierConfigManager { /** * The duration in seconds that platform call and message blocking is disabled after the user - * contacts emergency services. Platform considers values in the range 0 to 604800 (one week) as - * valid. See {@link android.provider.BlockedNumberContract#isBlocked(Context, String)}). + * contacts emergency services. Platform considers values for below cases: + * 1) 0 <= VALUE <= 604800(one week): the value will be used as the duration directly. + * 2) VALUE > 604800(one week): will use the default value as duration instead. + * 3) VALUE < 0: block will be disabled forever until user re-eanble block manually, + * the suggested value to disable forever is -1. + * See {@code android.provider.BlockedNumberContract#notifyEmergencyContact(Context)} + * See {@code android.provider.BlockedNumberContract#isBlocked(Context, String)}. */ public static final String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int"; + /** + * Determines whether to enable enhanced call blocking feature on the device. + * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED + * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE + * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE + * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN + * + *

    + * 1. For Single SIM(SS) device, it can be customized in both carrier_config_mccmnc.xml + * and vendor.xml. + *

    + * 2. For Dual SIM(DS) device, it should be customized in vendor.xml, since call blocking + * function is used regardless of SIM. + *

    + * If {@code true} enable enhanced call blocking feature on the device, {@code false} otherwise. + * @hide + */ + public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL = + "support_enhanced_call_blocking_bool"; + /** * For carriers which require an empty flash to be sent before sending the normal 3-way calling * flash, the duration in milliseconds of the empty flash to send. When {@code 0}, no empty @@ -2059,6 +2084,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL, false); sDefaults.putBoolean(KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL, false); + sDefaults.putBoolean(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL, false); // MMS defaults sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false); diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index e092d52d91bc131b6f3b642a7bb72d2d019211ad..08f8bb6494a04d87c59a1276852487bd5ee45c88 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; @@ -124,6 +127,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. * diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java index 105ddb0e8f2555c2f590578e53e902673c5f37f0..713ac00a2d3a5c20348c86a8f48e4b5d61871f26 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.Nullable; import android.os.Parcel; import android.text.TextUtils; @@ -181,6 +182,7 @@ public final class CellIdentityCdma extends CellIdentity { * @return The long alpha tag associated with the current scan result (may be the operator * name string or extended operator name string). May be null if unknown. */ + @Nullable public CharSequence getOperatorAlphaLong() { return mAlphaLong; } @@ -189,6 +191,7 @@ public final class CellIdentityCdma extends CellIdentity { * @return The short alpha tag associated with the current scan result (may be the operator * name string or extended operator name string). May be null if unknown. */ + @Nullable public CharSequence getOperatorAlphaShort() { return mAlphaShort; } diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index d35eb60916f31d43d1871d731f0b59d6b29a349d..aae7929b6799c918f8434ea214c3f6fc517fbbf9 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.Nullable; import android.os.Parcel; import android.text.TextUtils; @@ -191,6 +192,7 @@ public final class CellIdentityGsm extends CellIdentity { * @return The long alpha tag associated with the current scan result (may be the operator * name string or extended operator name string). May be null if unknown. */ + @Nullable public CharSequence getOperatorAlphaLong() { return mAlphaLong; } @@ -199,10 +201,16 @@ public final class CellIdentityGsm extends CellIdentity { * @return The short alpha tag associated with the current scan result (may be the operator * name string or extended operator name string). May be null if unknown. */ + @Nullable public CharSequence getOperatorAlphaShort() { 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 2b8eb5f3cca67a123bfdc9ad431477b393fb3262..9b3ef568751b778623c1ff0706fc4868988e3dd5 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.Nullable; import android.os.Parcel; import android.text.TextUtils; @@ -201,6 +202,7 @@ public final class CellIdentityLte extends CellIdentity { * @return The long alpha tag associated with the current scan result (may be the operator * name string or extended operator name string). May be null if unknown. */ + @Nullable public CharSequence getOperatorAlphaLong() { return mAlphaLong; } @@ -209,10 +211,17 @@ public final class CellIdentityLte extends CellIdentity { * @return The short alpha tag associated with the current scan result (may be the operator * name string or extended operator name string). May be null if unknown. */ + @Nullable public CharSequence getOperatorAlphaShort() { 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/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java index 992545d62408fd2440ab6738ef19b049d4961017..7475c74ea70c0ed4bf5fe4eb753229aca0c008a5 100644 --- a/telephony/java/android/telephony/CellIdentityTdscdma.java +++ b/telephony/java/android/telephony/CellIdentityTdscdma.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.Nullable; import android.os.Parcel; import android.text.TextUtils; @@ -34,6 +35,10 @@ public final class CellIdentityTdscdma extends CellIdentity { private final int mCid; // 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown. private final int mCpid; + // long alpha Operator Name String or Enhanced Operator Name String + private final String mAlphaLong; + // short alpha Operator Name String or Enhanced Operator Name String + private final String mAlphaShort; /** * @hide @@ -43,6 +48,8 @@ public final class CellIdentityTdscdma extends CellIdentity { mLac = Integer.MAX_VALUE; mCid = Integer.MAX_VALUE; mCpid = Integer.MAX_VALUE; + mAlphaLong = null; + mAlphaShort = null; } /** @@ -55,7 +62,7 @@ public final class CellIdentityTdscdma extends CellIdentity { * @hide */ public CellIdentityTdscdma(int mcc, int mnc, int lac, int cid, int cpid) { - this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid); + this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid, null, null); } /** @@ -65,6 +72,7 @@ public final class CellIdentityTdscdma extends CellIdentity { * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown * + * FIXME: This is a temporary constructor to facilitate migration. * @hide */ public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid) { @@ -72,10 +80,34 @@ public final class CellIdentityTdscdma extends CellIdentity { mLac = lac; mCid = cid; mCpid = cpid; + mAlphaLong = null; + mAlphaShort = null; + } + + /** + * @param mcc 3-digit Mobile Country Code in string format + * @param mnc 2 or 3-digit Mobile Network Code in string format + * @param lac 16-bit Location Area Code, 0..65535, INT_MAX if unknown + * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown + * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown + * @param alphal long alpha Operator Name String or Enhanced Operator Name String + * @param alphas short alpha Operator Name String or Enhanced Operator Name String + * + * @hide + */ + public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid, + String alphal, String alphas) { + super(TAG, TYPE_TDSCDMA, mcc, mnc); + mLac = lac; + mCid = cid; + mCpid = cpid; + mAlphaLong = alphal; + mAlphaShort = alphas; } private CellIdentityTdscdma(CellIdentityTdscdma cid) { - this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid, cid.mCpid); + this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid, + cid.mCpid, cid.mAlphaLong, cid.mAlphaShort); } CellIdentityTdscdma copy() { @@ -119,9 +151,31 @@ public final class CellIdentityTdscdma extends CellIdentity { return mCpid; } + /** + * @return The long alpha tag associated with the current scan result (may be the operator + * name string or extended operator name string). May be null if unknown. + * + * @hide + */ + @Nullable + public CharSequence getOperatorAlphaLong() { + return mAlphaLong; + } + + /** + * @return The short alpha tag associated with the current scan result (may be the operator + * name string or extended operator name string). May be null if unknown. + * + * @hide + */ + @Nullable + public CharSequence getOperatorAlphaShort() { + return mAlphaShort; + } + @Override public int hashCode() { - return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid); + return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid, mAlphaLong, mAlphaShort); } @Override @@ -139,7 +193,9 @@ public final class CellIdentityTdscdma extends CellIdentity { && TextUtils.equals(mMncStr, o.mMncStr) && mLac == o.mLac && mCid == o.mCid - && mCpid == o.mCpid; + && mCpid == o.mCpid + && mAlphaLong == o.mAlphaLong + && mAlphaShort == o.mAlphaShort; } @Override @@ -150,6 +206,8 @@ public final class CellIdentityTdscdma extends CellIdentity { .append(" mLac=").append(mLac) .append(" mCid=").append(mCid) .append(" mCpid=").append(mCpid) + .append(" mAlphaLong=").append(mAlphaLong) + .append(" mAlphaShort=").append(mAlphaShort) .append("}").toString(); } @@ -161,6 +219,8 @@ public final class CellIdentityTdscdma extends CellIdentity { dest.writeInt(mLac); dest.writeInt(mCid); dest.writeInt(mCpid); + dest.writeString(mAlphaLong); + dest.writeString(mAlphaShort); } /** Construct from Parcel, type has already been processed */ @@ -169,6 +229,8 @@ public final class CellIdentityTdscdma extends CellIdentity { mLac = in.readInt(); mCid = in.readInt(); mCpid = in.readInt(); + mAlphaLong = in.readString(); + mAlphaShort = in.readString(); if (DBG) log(toString()); } diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java index a5fd7dd97941ad5193b7710804c0cebaa8e61fca..52fa54f373d482d43c5037b44fd7b39f77b3ce15 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.Nullable; import android.os.Parcel; import android.text.TextUtils; @@ -182,6 +183,7 @@ public final class CellIdentityWcdma extends CellIdentity { * @return The long alpha tag associated with the current scan result (may be the operator * name string or extended operator name string). May be null if unknown. */ + @Nullable public CharSequence getOperatorAlphaLong() { return mAlphaLong; } @@ -190,6 +192,7 @@ public final class CellIdentityWcdma extends CellIdentity { * @return The short alpha tag associated with the current scan result (may be the operator * name string or extended operator name string). May be null if unknown. */ + @Nullable public CharSequence getOperatorAlphaShort() { return mAlphaShort; } @@ -206,6 +209,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 ce1b80c2c8605e0d66beae12e8ae0561d82b253f..81a966b7de2f61849b2d81d21db88c10cfb86294 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 7f43ee5f425c91e8290cb5298646ce3058b6a9d4..073c313a61df3426a8dd820daa03f59431d137bb 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/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 0446925f8cb4ef6630d329ba26b492a1a1c9d96f..0ff29825bfb3d2f24d5eedb20fdea7735991d88f 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -61,9 +61,6 @@ public class PhoneStateListener { /** * Listen for changes to the network signal strength (cellular). * {@more} - * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE - * READ_PHONE_STATE} - *

    * * @see #onSignalStrengthChanged * @@ -76,7 +73,8 @@ public class PhoneStateListener { * Listen for changes to the message-waiting indicator. * {@more} * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE - * READ_PHONE_STATE} + * READ_PHONE_STATE} or that the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges}). *

    * Example: The status bar uses this to determine when to display the * voicemail icon. @@ -89,7 +87,9 @@ public class PhoneStateListener { * Listen for changes to the call-forwarding indicator. * {@more} * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE - * READ_PHONE_STATE} + * READ_PHONE_STATE} or that the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges}). + * * @see #onCallForwardingIndicatorChanged */ public static final int LISTEN_CALL_FORWARDING_INDICATOR = 0x00000008; @@ -430,8 +430,9 @@ public class PhoneStateListener { * Callback invoked when device call state changes. * @param state call state * @param phoneNumber call phone number. If application does not have - * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission, an empty - * string will be passed as an argument. + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission or carrier + * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be + * passed as an argument. * * @see TelephonyManager#CALL_STATE_IDLE * @see TelephonyManager#CALL_STATE_RINGING diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 82a7450945f794475dd76ac61b0d653cf1c1fa01..9c831b9be0ddda54df018bbd24c87fb14af3daae 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -221,7 +221,7 @@ public class ServiceState implements Parcelable { public static final int ROAMING_TYPE_INTERNATIONAL = 3; /** - * Unknown ID. Could be returned by {@link #getNetworkId()} or {@link #getSystemId()} + * Unknown ID. Could be returned by {@link #getCdmaNetworkId()} or {@link #getCdmaSystemId()} */ public static final int UNKNOWN_ID = -1; @@ -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)) @@ -1217,7 +1222,7 @@ public class ServiceState implements Parcelable { /** @hide */ @TestApi - public void setSystemAndNetworkId(int systemId, int networkId) { + public void setCdmaSystemAndNetworkId(int systemId, int networkId) { this.mSystemId = systemId; this.mNetworkId = networkId; } @@ -1383,7 +1388,7 @@ public class ServiceState implements Parcelable { * within a wireless system. (Defined in 3GPP2 C.S0023 3.4.8) * @return The CDMA NID or {@link #UNKNOWN_ID} if not available. */ - public int getNetworkId() { + public int getCdmaNetworkId() { return this.mNetworkId; } @@ -1392,7 +1397,7 @@ public class ServiceState implements Parcelable { * system. (Defined in 3GPP2 C.S0023 3.4.8) * @return The CDMA SID or {@link #UNKNOWN_ID} if not available. */ - public int getSystemId() { + public int getCdmaSystemId() { return this.mSystemId; } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 7b0df77d8be359b14e23e6ee6559e4470b3099c3..22136b8ccb73216590af93ce28381e42349308ac 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.RequiresPermission; +import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; import android.app.ActivityThread; import android.app.PendingIntent; @@ -343,15 +344,16 @@ public final class SmsManager { * applications. Intended for internal carrier use only. *

    * - *

    Requires Permission: - * {@link android.Manifest.permission#SEND_SMS} and - * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier - * privileges. - *

    + *

    Requires Permission: Both {@link android.Manifest.permission#SEND_SMS} and + * {@link android.Manifest.permission#MODIFY_PHONE_STATE}, or that the calling app has carrier + * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), or that the calling app is + * the default IMS app (see + * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}). * * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent) */ @SystemApi + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(allOf = { android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.SEND_SMS diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 4a6143788cc1b17bd968c7bd4e50f3bfa7dcc9ce..472a6fbc0c1b56336433aab369a979c6cce8af81 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -25,6 +25,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.BroadcastOptions; @@ -42,7 +43,6 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.ServiceManager.ServiceNotFoundException; import android.util.DisplayMetrics; import com.android.internal.telephony.IOnSubscriptionsChangedListener; @@ -59,9 +59,6 @@ import java.util.concurrent.TimeUnit; /** * SubscriptionManager is the application interface to SubscriptionController * and provides information about the current Telephony Subscriptions. - *

    - * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE unless otherwise - * specified. */ @SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) public class SubscriptionManager { @@ -660,9 +657,15 @@ public class SubscriptionManager { /** * Get the active SubscriptionInfo with the input subId. * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges}). + * * @param subId The unique SubscriptionInfo key in database. * @return SubscriptionInfo, maybe null if its not active. */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public SubscriptionInfo getActiveSubscriptionInfo(int subId) { if (VDBG) logd("[getActiveSubscriptionInfo]+ subId=" + subId); if (!isValidSubscriptionId(subId)) { @@ -716,9 +719,16 @@ public class SubscriptionManager { /** * Get the active SubscriptionInfo associated with the slotIndex + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges}). + * * @param slotIndex the slot which the subscription is inserted * @return SubscriptionInfo, maybe null if its not active */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) { if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIndex=" + slotIndex); if (!isValidSlotIndex(slotIndex)) { @@ -770,6 +780,11 @@ public class SubscriptionManager { * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}. * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges}). In the latter case, only records accessible + * to the calling app are returned. + * * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device. *

      *
    • @@ -786,6 +801,8 @@ public class SubscriptionManager { *
    • *
    */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public List getActiveSubscriptionInfoList() { List result = null; @@ -928,10 +945,18 @@ public class SubscriptionManager { } /** + * + * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges}). In the latter case, the count will include + * only those subscriptions accessible to the caller. + * * @return the current number of active subscriptions. There is no guarantee the value * returned by this method will be the same as the length of the list returned by * {@link #getActiveSubscriptionInfoList}. */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getActiveSubscriptionInfoCount() { int result = 0; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index aa76e9d554b615f6cf24d5cfdf5b0b362297f629..0b15191951da48353eb02a62cc1104a497f22c03 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SuppressAutoDoc; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; @@ -53,7 +54,6 @@ import android.telephony.ims.aidl.IImsConfig; import android.telephony.ims.aidl.IImsMmTelFeature; import android.telephony.ims.aidl.IImsRcsFeature; import android.telephony.ims.aidl.IImsRegistration; -import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.Log; @@ -1082,7 +1082,7 @@ public class TelephonyManager { /** * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates - * the updated carrier id {@link TelephonyManager#getAndroidCarrierIdForSubscription()} of + * the updated carrier id {@link TelephonyManager#getSimCarrierId()} of * the current subscription. *

    Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or * the carrier cannot be identified. @@ -1092,7 +1092,7 @@ public class TelephonyManager { /** * An string extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which * indicates the updated carrier name of the current subscription. - * {@see TelephonyManager#getSubscriptionCarrierName()} + * {@see TelephonyManager#getSimCarrierIdName()} *

    Carrier name is a user-facing name of the carrier id {@link #EXTRA_CARRIER_ID}, * usually the brand name of the subsidiary (e.g. T-Mobile). */ @@ -1114,7 +1114,11 @@ public class TelephonyManager { * Returns the software version number for the device, for example, * the IMEI/SV for GSM phones. Return null if the software version is * not available. + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion() { return getDeviceSoftwareVersion(getSlotIndex()); @@ -1146,10 +1150,14 @@ public class TelephonyManager { * Returns the unique device ID, for example, the IMEI for GSM and the MEID * or ESN for CDMA phones. Return null if device ID is not available. * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * * @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns * MEID for CDMA. */ @Deprecated + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceId() { try { @@ -1168,12 +1176,16 @@ public class TelephonyManager { * Returns the unique device ID of a subscription, for example, the IMEI for * GSM and the MEID for CDMA phones. Return null if device ID is not available. * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * * @param slotIndex of which deviceID is returned * * @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns * MEID for CDMA. */ @Deprecated + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceId(int slotIndex) { // FIXME this assumes phoneId == slotIndex @@ -1192,7 +1204,11 @@ public class TelephonyManager { /** * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not * available. + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getImei() { return getImei(getSlotIndex()); @@ -1202,8 +1218,12 @@ public class TelephonyManager { * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not * available. * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * * @param slotIndex of which IMEI is returned */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getImei(int slotIndex) { ITelephony telephony = getITelephony(); @@ -1220,7 +1240,11 @@ public class TelephonyManager { /** * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available. + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getMeid() { return getMeid(getSlotIndex()); @@ -1229,8 +1253,12 @@ public class TelephonyManager { /** * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available. * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * * @param slotIndex of which MEID is returned */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getMeid(int slotIndex) { ITelephony telephony = getITelephony(); @@ -1247,10 +1275,11 @@ public class TelephonyManager { /** * Returns the Network Access Identifier (NAI). Return null if NAI is not available. - *

    - * Requires Permission: - * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getNai() { return getNaiBySubscriberId(getSubId()); @@ -1747,10 +1776,17 @@ public class TelephonyManager { * invalid subscription ID is pinned to the TelephonyManager, the returned config will contain * default values. * + *

    This method may take several seconds to complete, so it should only be called from a + * worker thread. + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * * @see CarrierConfigManager#getConfigForSubId(int) * @see #createForSubscriptionId(int) * @see #createForPhoneAccountHandle(PhoneAccountHandle) */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public PersistableBundle getCarrierConfig() { @@ -1835,47 +1871,52 @@ public class TelephonyManager { /* * When adding a network type to the list below, make sure to add the correct icon to * MobileSignalController.mapIconSets(). + * Do not add negative types. */ /** Network type is unknown */ - public static final int NETWORK_TYPE_UNKNOWN = 0; + public static final int NETWORK_TYPE_UNKNOWN = TelephonyProtoEnums.NETWORK_TYPE_UNKNOWN; // = 0. /** Current network is GPRS */ - public static final int NETWORK_TYPE_GPRS = 1; + public static final int NETWORK_TYPE_GPRS = TelephonyProtoEnums.NETWORK_TYPE_GPRS; // = 1. /** Current network is EDGE */ - public static final int NETWORK_TYPE_EDGE = 2; + public static final int NETWORK_TYPE_EDGE = TelephonyProtoEnums.NETWORK_TYPE_EDGE; // = 2. /** Current network is UMTS */ - public static final int NETWORK_TYPE_UMTS = 3; + public static final int NETWORK_TYPE_UMTS = TelephonyProtoEnums.NETWORK_TYPE_UMTS; // = 3. /** Current network is CDMA: Either IS95A or IS95B*/ - public static final int NETWORK_TYPE_CDMA = 4; + public static final int NETWORK_TYPE_CDMA = TelephonyProtoEnums.NETWORK_TYPE_CDMA; // = 4. /** Current network is EVDO revision 0*/ - public static final int NETWORK_TYPE_EVDO_0 = 5; + public static final int NETWORK_TYPE_EVDO_0 = TelephonyProtoEnums.NETWORK_TYPE_EVDO_0; // = 5. /** Current network is EVDO revision A*/ - public static final int NETWORK_TYPE_EVDO_A = 6; + public static final int NETWORK_TYPE_EVDO_A = TelephonyProtoEnums.NETWORK_TYPE_EVDO_A; // = 6. /** Current network is 1xRTT*/ - public static final int NETWORK_TYPE_1xRTT = 7; + public static final int NETWORK_TYPE_1xRTT = TelephonyProtoEnums.NETWORK_TYPE_1XRTT; // = 7. /** Current network is HSDPA */ - public static final int NETWORK_TYPE_HSDPA = 8; + public static final int NETWORK_TYPE_HSDPA = TelephonyProtoEnums.NETWORK_TYPE_HSDPA; // = 8. /** Current network is HSUPA */ - public static final int NETWORK_TYPE_HSUPA = 9; + public static final int NETWORK_TYPE_HSUPA = TelephonyProtoEnums.NETWORK_TYPE_HSUPA; // = 9. /** Current network is HSPA */ - public static final int NETWORK_TYPE_HSPA = 10; + public static final int NETWORK_TYPE_HSPA = TelephonyProtoEnums.NETWORK_TYPE_HSPA; // = 10. /** Current network is iDen */ - public static final int NETWORK_TYPE_IDEN = 11; + public static final int NETWORK_TYPE_IDEN = TelephonyProtoEnums.NETWORK_TYPE_IDEN; // = 11. /** Current network is EVDO revision B*/ - public static final int NETWORK_TYPE_EVDO_B = 12; + public static final int NETWORK_TYPE_EVDO_B = TelephonyProtoEnums.NETWORK_TYPE_EVDO_B; // = 12. /** Current network is LTE */ - public static final int NETWORK_TYPE_LTE = 13; + public static final int NETWORK_TYPE_LTE = TelephonyProtoEnums.NETWORK_TYPE_LTE; // = 13. /** Current network is eHRPD */ - public static final int NETWORK_TYPE_EHRPD = 14; + public static final int NETWORK_TYPE_EHRPD = TelephonyProtoEnums.NETWORK_TYPE_EHRPD; // = 14. /** Current network is HSPA+ */ - public static final int NETWORK_TYPE_HSPAP = 15; + public static final int NETWORK_TYPE_HSPAP = TelephonyProtoEnums.NETWORK_TYPE_HSPAP; // = 15. /** Current network is GSM */ - public static final int NETWORK_TYPE_GSM = 16; + public static final int NETWORK_TYPE_GSM = TelephonyProtoEnums.NETWORK_TYPE_GSM; // = 16. /** Current network is TD_SCDMA */ - public static final int NETWORK_TYPE_TD_SCDMA = 17; + public static final int NETWORK_TYPE_TD_SCDMA = + TelephonyProtoEnums.NETWORK_TYPE_TD_SCDMA; // = 17. /** Current network is IWLAN */ - public static final int NETWORK_TYPE_IWLAN = 18; + public static final int NETWORK_TYPE_IWLAN = TelephonyProtoEnums.NETWORK_TYPE_IWLAN; // = 18. /** Current network is LTE_CA {@hide} */ - public static final int NETWORK_TYPE_LTE_CA = 19; + public static final int NETWORK_TYPE_LTE_CA = TelephonyProtoEnums.NETWORK_TYPE_LTE_CA; // = 19. + + /** Max network type number. Update as new types are added. Don't add negative types. {@hide} */ + public static final int MAX_NETWORK_TYPE = NETWORK_TYPE_LTE_CA; /** * @return the NETWORK_TYPE_xxxx for current data connection. */ @@ -1949,6 +1990,9 @@ public class TelephonyManager { * If this object has been created with {@link #createForSubscriptionId}, applies to the given * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * * @return the network type * * @see #NETWORK_TYPE_UNKNOWN @@ -1968,6 +2012,7 @@ public class TelephonyManager { * @see #NETWORK_TYPE_EHRPD * @see #NETWORK_TYPE_HSPAP */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getDataNetworkType() { return getDataNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId())); @@ -2002,7 +2047,11 @@ public class TelephonyManager { /** * Returns the NETWORK_TYPE_xxxx for voice + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getVoiceNetworkType() { return getVoiceNetworkType(getSubId()); @@ -2588,7 +2637,11 @@ public class TelephonyManager { /** * Returns the serial number of the SIM, if applicable. Return null if it is * unavailable. + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getSimSerialNumber() { return getSimSerialNumber(getSubId()); @@ -2713,7 +2766,11 @@ public class TelephonyManager { /** * Returns the unique subscriber ID, for example, the IMSI for a GSM phone. * Return null if it is unavailable. + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getSubscriberId() { return getSubscriberId(getSubId()); @@ -2877,7 +2934,11 @@ public class TelephonyManager { /** * Returns the Group Identifier Level1 for a GSM phone. * Return null if it is unavailable. + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1() { try { @@ -2918,9 +2979,15 @@ public class TelephonyManager { /** * Returns the phone number string for line 1, for example, the MSISDN * for a GSM phone. Return null if it is unavailable. - *

    - * The default SMS app can also use this. + * + *

    Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, + * {@link android.Manifest.permission#READ_SMS READ_SMS}, + * {@link android.Manifest.permission#READ_PHONE_NUMBERS READ_PHONE_NUMBERS}, + * that the caller is the default SMS app, + * or that the caller has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges or default SMS app @RequiresPermission(anyOf = { android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, @@ -2975,8 +3042,7 @@ public class TelephonyManager { * change the actual MSISDN/MDN. To unset alphatag or number, pass in a null * value. * - *

    Requires that the calling app has carrier privileges. - * @see #hasCarrierPrivileges + *

    Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param alphaTag alpha-tagging of the dailing nubmer * @param number The dialing number @@ -2992,8 +3058,7 @@ public class TelephonyManager { * change the actual MSISDN/MDN. To unset alphatag or number, pass in a null * value. * - *

    Requires that the calling app has carrier privileges. - * @see #hasCarrierPrivileges + *

    Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId the subscriber that the alphatag and dialing number belongs to. * @param alphaTag alpha-tagging of the dailing nubmer @@ -3112,7 +3177,11 @@ public class TelephonyManager { /** * Returns the voice mail number. Return null if it is unavailable. + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber() { return getVoiceMailNumber(getSubId()); @@ -3173,8 +3242,7 @@ public class TelephonyManager { /** * Sets the voice mail number. * - *

    Requires that the calling app has carrier privileges. - * @see #hasCarrierPrivileges + *

    Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param alphaTag The alpha tag to display. * @param number The voicemail number. @@ -3186,8 +3254,7 @@ public class TelephonyManager { /** * Sets the voicemail number for the given subscriber. * - *

    Requires that the calling app has carrier privileges. - * @see #hasCarrierPrivileges + *

    Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription id. * @param alphaTag The alpha tag to display. @@ -3208,9 +3275,9 @@ public class TelephonyManager { /** * Enables or disables the visual voicemail client for a phone account. * - *

    Requires that the calling app is the default dialer, or has carrier privileges, or - * has permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. - * @see #hasCarrierPrivileges + *

    Requires that the calling app is the default dialer, or has carrier privileges (see + * {@link #hasCarrierPrivileges}), or has permission + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. * * @param phoneAccountHandle the phone account to change the client state * @param enabled the new state of the client @@ -3273,11 +3340,15 @@ public class TelephonyManager { * to the TelephonyManager. Returns {@code null} when there is no package responsible for * processing visual voicemail for the subscription. * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * * @see #createForSubscriptionId(int) * @see #createForPhoneAccountHandle(PhoneAccountHandle) * @see VisualVoicemailService */ @Nullable + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVisualVoicemailPackageName() { try { @@ -3520,15 +3591,14 @@ public class TelephonyManager { * Sets the voice activation state * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the + * calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param activationState The voice activation state * @see #SIM_ACTIVATION_STATE_UNKNOWN * @see #SIM_ACTIVATION_STATE_ACTIVATING * @see #SIM_ACTIVATION_STATE_ACTIVATED * @see #SIM_ACTIVATION_STATE_DEACTIVATED - * @see #hasCarrierPrivileges * @hide */ @SystemApi @@ -3541,8 +3611,8 @@ public class TelephonyManager { * Sets the voice activation state for the given subscriber. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the + * calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription id. * @param activationState The voice activation state of the given subscriber. @@ -3550,7 +3620,6 @@ public class TelephonyManager { * @see #SIM_ACTIVATION_STATE_ACTIVATING * @see #SIM_ACTIVATION_STATE_ACTIVATED * @see #SIM_ACTIVATION_STATE_DEACTIVATED - * @see #hasCarrierPrivileges * @hide */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -3568,8 +3637,8 @@ public class TelephonyManager { * Sets the data activation state * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the + * calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param activationState The data activation state * @see #SIM_ACTIVATION_STATE_UNKNOWN @@ -3577,7 +3646,6 @@ public class TelephonyManager { * @see #SIM_ACTIVATION_STATE_ACTIVATED * @see #SIM_ACTIVATION_STATE_DEACTIVATED * @see #SIM_ACTIVATION_STATE_RESTRICTED - * @see #hasCarrierPrivileges * @hide */ @SystemApi @@ -3590,8 +3658,8 @@ public class TelephonyManager { * Sets the data activation state for the given subscriber. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the + * calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription id. * @param activationState The data activation state of the given subscriber. @@ -3600,7 +3668,6 @@ public class TelephonyManager { * @see #SIM_ACTIVATION_STATE_ACTIVATED * @see #SIM_ACTIVATION_STATE_DEACTIVATED * @see #SIM_ACTIVATION_STATE_RESTRICTED - * @see #hasCarrierPrivileges * @hide */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -3618,15 +3685,14 @@ public class TelephonyManager { * Returns the voice activation state * *

    Requires Permission: - * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} - * Or the calling app has carrier privileges. + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @return voiceActivationState * @see #SIM_ACTIVATION_STATE_UNKNOWN * @see #SIM_ACTIVATION_STATE_ACTIVATING * @see #SIM_ACTIVATION_STATE_ACTIVATED * @see #SIM_ACTIVATION_STATE_DEACTIVATED - * @see #hasCarrierPrivileges * @hide */ @SystemApi @@ -3639,8 +3705,8 @@ public class TelephonyManager { * Returns the voice activation state for the given subscriber. * *

    Requires Permission: - * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} - * Or the calling app has carrier privileges. + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription id. * @@ -3649,7 +3715,6 @@ public class TelephonyManager { * @see #SIM_ACTIVATION_STATE_ACTIVATING * @see #SIM_ACTIVATION_STATE_ACTIVATED * @see #SIM_ACTIVATION_STATE_DEACTIVATED - * @see #hasCarrierPrivileges * @hide */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @@ -3668,8 +3733,8 @@ public class TelephonyManager { * Returns the data activation state * *

    Requires Permission: - * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} - * Or the calling app has carrier privileges. + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @return dataActivationState for the given subscriber * @see #SIM_ACTIVATION_STATE_UNKNOWN @@ -3677,7 +3742,6 @@ public class TelephonyManager { * @see #SIM_ACTIVATION_STATE_ACTIVATED * @see #SIM_ACTIVATION_STATE_DEACTIVATED * @see #SIM_ACTIVATION_STATE_RESTRICTED - * @see #hasCarrierPrivileges * @hide */ @SystemApi @@ -3690,8 +3754,8 @@ public class TelephonyManager { * Returns the data activation state for the given subscriber. * *

    Requires Permission: - * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} - * Or the calling app has carrier privileges. + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription id. * @@ -3701,7 +3765,6 @@ public class TelephonyManager { * @see #SIM_ACTIVATION_STATE_ACTIVATED * @see #SIM_ACTIVATION_STATE_DEACTIVATED * @see #SIM_ACTIVATION_STATE_RESTRICTED - * @see #hasCarrierPrivileges * @hide */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @@ -3749,7 +3812,11 @@ public class TelephonyManager { /** * Retrieves the alphabetic identifier associated with the voice * mail number. + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag() { return getVoiceMailAlphaTag(getSubId()); @@ -3778,9 +3845,8 @@ public class TelephonyManager { } /** - * Send the special dialer code. The IPC caller must be the current default dialer or has - * carrier privileges. - * @see #hasCarrierPrivileges + * Send the special dialer code. The IPC caller must be the current default dialer or have + * carrier privileges (see {@link #hasCarrierPrivileges}). * * @param inputCode The special dialer code to send * @@ -4304,8 +4370,8 @@ public class TelephonyManager { * Input parameters equivalent to TS 27.007 AT+CCHO command. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param AID Application id. See ETSI 102.221 and 101.220. * @return an IccOpenLogicalChannelResponse object. @@ -4322,8 +4388,8 @@ public class TelephonyManager { * Input parameters equivalent to TS 27.007 AT+CCHO command. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param AID Application id. See ETSI 102.221 and 101.220. * @param p2 P2 parameter (described in ISO 7816-4). @@ -4339,8 +4405,8 @@ public class TelephonyManager { * Input parameters equivalent to TS 27.007 AT+CCHO command. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription to use. * @param AID Application id. See ETSI 102.221 and 101.220. @@ -4365,8 +4431,8 @@ public class TelephonyManager { * Input parameters equivalent to TS 27.007 AT+CCHC command. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param channel is the channel id to be closed as retruned by a successful * iccOpenLogicalChannel. @@ -4382,8 +4448,8 @@ public class TelephonyManager { * Input parameters equivalent to TS 27.007 AT+CCHC command. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription to use. * @param channel is the channel id to be closed as retruned by a successful @@ -4408,8 +4474,8 @@ public class TelephonyManager { * Input parameters equivalent to TS 27.007 AT+CGLA command. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param channel is the channel id to be closed as returned by a successful * iccOpenLogicalChannel. @@ -4435,8 +4501,8 @@ public class TelephonyManager { * Input parameters equivalent to TS 27.007 AT+CGLA command. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription to use. * @param channel is the channel id to be closed as returned by a successful @@ -4471,8 +4537,8 @@ public class TelephonyManager { * Input parameters equivalent to TS 27.007 AT+CSIM command. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param cla Class of the APDU command. * @param instruction Instruction of the APDU command. @@ -4496,8 +4562,8 @@ public class TelephonyManager { * Input parameters equivalent to TS 27.007 AT+CSIM command. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription to use. * @param cla Class of the APDU command. @@ -4528,8 +4594,8 @@ public class TelephonyManager { * Returns the response APDU for a command APDU sent through SIM_IO. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param fileID * @param command @@ -4548,8 +4614,8 @@ public class TelephonyManager { * Returns the response APDU for a command APDU sent through SIM_IO. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription to use. * @param fileID @@ -4577,8 +4643,8 @@ public class TelephonyManager { * Send ENVELOPE to the SIM and return the response. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param content String containing SAT/USAT response in hexadecimal * format starting with command tag. See TS 102 223 for @@ -4595,8 +4661,8 @@ public class TelephonyManager { * Send ENVELOPE to the SIM and return the response. * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription to use. * @param content String containing SAT/USAT response in hexadecimal @@ -4621,10 +4687,10 @@ public class TelephonyManager { /** * Read one of the NV items defined in com.android.internal.telephony.RadioNVItems. * Used for device configuration by some CDMA operators. - *

    - * Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + *

    Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param itemID the ID of the item to read. * @return the NV item as a String, or null on any failure. @@ -4647,10 +4713,10 @@ public class TelephonyManager { /** * Write one of the NV items defined in com.android.internal.telephony.RadioNVItems. * Used for device configuration by some CDMA operators. - *

    - * Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + *

    Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param itemID the ID of the item to read. * @param itemValue the value to write, as a String. @@ -4674,10 +4740,10 @@ public class TelephonyManager { /** * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage. * Used for device configuration by some CDMA operators. - *

    - * Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + *

    Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param preferredRoamingList byte array containing the new PRL. * @return true on success; false on any failure. @@ -4701,10 +4767,10 @@ public class TelephonyManager { * Perform the specified type of NV config reset. The radio will be taken offline * and the device must be rebooted after the operation. Used for device * configuration by some CDMA operators. - *

    - * Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + *

    Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param resetType reset type: 1: reload NV reset, 2: erase NV reset, 3: factory NV reset * @return true on success; false on any failure. @@ -5052,8 +5118,8 @@ public class TelephonyManager { * Returns the response of authentication for the default subscription. * Returns null if the authentication hasn't been successful * - *

    Requires that the calling app has carrier privileges or READ_PRIVILEGED_PHONE_STATE - * permission. + *

    Requires Permission: READ_PRIVILEGED_PHONE_STATE or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param appType the icc application type, like {@link #APPTYPE_USIM} * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or @@ -5061,9 +5127,10 @@ public class TelephonyManager { * @param data authentication challenge data, base64 encoded. * See 3GPP TS 31.102 7.1.2 for more details. * @return the response of authentication, or null if not available - * - * @see #hasCarrierPrivileges */ + // TODO(b/73660190): This should probably require MODIFY_PHONE_STATE, not + // READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since + // it's not public API. public String getIccAuthentication(int appType, int authType, String data) { return getIccAuthentication(getSubId(), appType, authType, data); } @@ -5072,7 +5139,7 @@ public class TelephonyManager { * Returns the response of USIM Authentication for specified subId. * Returns null if the authentication hasn't been successful * - *

    Requires that the calling app has carrier privileges. + *

    Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId subscription ID used for authentication * @param appType the icc application type, like {@link #APPTYPE_USIM} @@ -5081,8 +5148,6 @@ public class TelephonyManager { * @param data authentication challenge data, base64 encoded. * See 3GPP TS 31.102 7.1.2 for more details. * @return the response of authentication, or null if not available - * - * @see #hasCarrierPrivileges * @hide */ public String getIccAuthentication(int subId, int appType, int authType, String data) { @@ -5103,8 +5168,12 @@ public class TelephonyManager { * Returns an array of Forbidden PLMNs from the USIM App * Returns null if the query fails. * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * * @return an array of forbidden PLMNs or null if not available */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String[] getForbiddenPlmns() { return getForbiddenPlmns(getSubId(), APPTYPE_USIM); @@ -5125,7 +5194,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) { @@ -5275,19 +5344,18 @@ public class TelephonyManager { } /** - * Determines if emergency calling is allowed for the MMTEL feature on the slot provided. - * @param slotIndex The SIM slot of the MMTEL feature - * @return true if emergency calling is allowed, false otherwise. + * @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 isEmergencyMmTelAvailable(int slotIndex) { + public boolean isResolvingImsBinding() { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.isEmergencyMmTelAvailable(slotIndex); + return telephony.isResolvingImsBinding(); } } catch (RemoteException e) { - Rlog.e(TAG, "isEmergencyMmTelAvailable, RemoteException: " + e.getMessage()); + Rlog.e(TAG, "isResolvingImsBinding, RemoteException: " + e.getMessage()); } return false; } @@ -5310,10 +5378,10 @@ public class TelephonyManager { /** * Get the preferred network type. * Used for device configuration by some CDMA operators. - *

    - * Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + *

    Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @return the preferred network type, defined in RILConstants.java. * @hide @@ -5333,11 +5401,12 @@ public class TelephonyManager { /** * Sets the network selection mode to automatic. - *

    - * Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + *

    Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic() { try { @@ -5353,15 +5422,14 @@ public class TelephonyManager { } /** - * Perform a radio scan and return the list of avialble networks. + * Perform a radio scan and return the list of available networks. * * The return value is a list of the OperatorInfo of the networks found. Note that this * scan can take a long time (sometimes minutes) to happen. * - *

    - * Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + *

    Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @hide * TODO: Add an overload that takes no args. @@ -5385,17 +5453,19 @@ public class TelephonyManager { * This method is asynchronous, so the network scan results will be returned by callback. * The returned NetworkScan will contain a callback method which can be used to stop the scan. * - *

    - * Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. - * @see #hasCarrierPrivileges() + *

    Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param request Contains all the RAT with bands/channels that need to be scanned. - * @param executor The executor through which the callback should be invoked. + * @param executor The executor through which the callback should be invoked. Since the scan + * request may trigger multiple callbacks and they must be invoked in the same order as + * they are received by the platform, the user should provide an executor which executes + * tasks one at a time in serial order. For example AsyncTask.SERIAL_EXECUTOR. * @param callback Returns network scan results or errors. * @return A NetworkScan obj which contains a callback which can be used to stop the scan. */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public NetworkScan requestNetworkScan( NetworkScanRequest request, Executor executor, @@ -5417,16 +5487,15 @@ public class TelephonyManager { @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public NetworkScan requestNetworkScan( NetworkScanRequest request, TelephonyScanManager.NetworkScanCallback callback) { - return requestNetworkScan(request, AsyncTask.THREAD_POOL_EXECUTOR, callback); + return requestNetworkScan(request, AsyncTask.SERIAL_EXECUTOR, callback); } /** * Ask the radio to connect to the input network and change selection mode to manual. * - *

    - * Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + *

    Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param operatorNumeric the PLMN ID of the network to select. * @param persistSelection whether the selection will persist until reboot. If true, only allows @@ -5434,6 +5503,7 @@ public class TelephonyManager { * normal network selection next time. * @return true on success; false on any failure. */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(String operatorNumeric, boolean persistSelection) { try { @@ -5453,10 +5523,10 @@ public class TelephonyManager { /** * Set the preferred network type. * Used for device configuration by some CDMA operators. - *

    - * Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} - * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + *

    Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId the id of the subscription to set the preferred network type for. * @param networkType the preferred network type, defined in RILConstants.java. @@ -5480,9 +5550,7 @@ public class TelephonyManager { /** * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA. * - *

    - * Requires that the calling app has carrier privileges. - * @see #hasCarrierPrivileges + *

    Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @return true on success; false on any failure. */ @@ -5493,9 +5561,7 @@ public class TelephonyManager { /** * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA. * - *

    - * Requires that the calling app has carrier privileges. - * @see #hasCarrierPrivileges + *

    Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @return true on success; false on any failure. * @hide @@ -5585,8 +5651,7 @@ public class TelephonyManager { * brand value input. To unset the value, the same function should be * called with a null brand value. * - *

    Requires that the calling app has carrier privileges. - * @see #hasCarrierPrivileges + *

    Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param brand The brand name to display/set. * @return true if the operation was executed correctly. @@ -5603,8 +5668,7 @@ public class TelephonyManager { * brand value input. To unset the value, the same function should be * called with a null brand value. * - *

    Requires that the calling app has carrier privileges. - * @see #hasCarrierPrivileges + *

    Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param subId The subscription to use. * @param brand The brand name to display/set. @@ -6258,15 +6322,15 @@ public class TelephonyManager { * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the - * calling app has carrier privileges. + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param enable Whether to enable mobile data. * - * @see #hasCarrierPrivileges * @deprecated use {@link #setUserMobileDataEnabled(boolean)} instead. */ @Deprecated + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean enable) { setUserMobileDataEnabled(enable); @@ -6303,7 +6367,7 @@ public class TelephonyManager { *

    Requires one of the following permissions: * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE}, * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the - * calling app has carrier privileges. + * calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * *

    Note that this does not take into account any data restrictions that may be present on the * calling app. Such restrictions may be inspected with @@ -6311,7 +6375,6 @@ public class TelephonyManager { * * @return true if mobile data is enabled. * - * @see #hasCarrierPrivileges * @deprecated use {@link #isUserMobileDataEnabled()} instead. */ @Deprecated @@ -7082,7 +7145,11 @@ public class TelephonyManager { /** * Returns the current {@link ServiceState} information. + * + *

    Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public ServiceState getServiceState() { return getServiceStateForSubscriber(getSubId()); @@ -7128,14 +7195,14 @@ public class TelephonyManager { /** * Sets the per-account voicemail ringtone. * - *

    Requires that the calling app is the default dialer, or has carrier privileges, or has - * permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. + *

    Requires that the calling app is the default dialer, or has carrier privileges (see + * {@link #hasCarrierPrivileges}, or has permission + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. * * @param phoneAccountHandle The handle for the {@link PhoneAccount} for which to set the * voicemail ringtone. * @param uri The URI for the ringtone to play when receiving a voicemail from a specific * PhoneAccount. - * @see #hasCarrierPrivileges * * @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS} * instead. @@ -7173,14 +7240,14 @@ public class TelephonyManager { /** * Sets the per-account preference whether vibration is enabled for voicemail notifications. * - *

    Requires that the calling app is the default dialer, or has carrier privileges, or has - * permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. + *

    Requires that the calling app is the default dialer, or has carrier privileges (see + * {@link #hasCarrierPrivileges}, or has permission + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. * * @param phoneAccountHandle The handle for the {@link PhoneAccount} for which to set the * voicemail vibration setting. * @param enabled Whether to enable or disable vibration for voicemail notifications from a * specific PhoneAccount. - * @see #hasCarrierPrivileges * * @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS} * instead. @@ -7201,8 +7268,8 @@ public class TelephonyManager { /** * Returns carrier id of the current subscription. *

    To recognize a carrier (including MVNO) as a first-class identity, Android assigns each - * carrier with a canonical integer a.k.a. android carrier id. The Android carrier ID is an - * Android platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in + * carrier with a canonical integer a.k.a. carrier id. The carrier ID is an Android + * platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in * here * *

    Apps which have carrier-specific configurations or business logic can use the carrier id @@ -7211,7 +7278,7 @@ public class TelephonyManager { * @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the * subscription is unavailable or the carrier cannot be identified. */ - public int getAndroidCarrierIdForSubscription() { + public int getSimCarrierId() { try { ITelephony service = getITelephony(); if (service != null) { @@ -7224,18 +7291,18 @@ public class TelephonyManager { } /** - * Returns carrier name of the current subscription. - *

    Carrier name is a user-facing name of carrier id - * {@link #getAndroidCarrierIdForSubscription()}, usually the brand name of the subsidiary + * Returns carrier id name of the current subscription. + *

    Carrier id name is a user-facing name of carrier id + * {@link #getSimCarrierId()}, usually the brand name of the subsidiary * (e.g. T-Mobile). Each carrier could configure multiple {@link #getSimOperatorName() SPN} but * should have a single carrier name. Carrier name is not a canonical identity, - * use {@link #getAndroidCarrierIdForSubscription()} instead. + * use {@link #getSimCarrierId()} instead. *

    The returned carrier name is unlocalized. * * @return Carrier name of the current subscription. Return {@code null} if the subscription is * unavailable or the carrier cannot be identified. */ - public CharSequence getAndroidCarrierNameForSubscription() { + public CharSequence getSimCarrierIdName() { try { ITelephony service = getITelephony(); if (service != null) { @@ -7601,12 +7668,10 @@ public class TelephonyManager { * Otherwise, it applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} * *

    Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the - * calling app has carrier privileges. + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling + * app has carrier privileges (see {@link #hasCarrierPrivileges}. * * @param enable Whether to enable mobile data. - * - * @see #hasCarrierPrivileges */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserMobileDataEnabled(boolean enable) { @@ -7624,15 +7689,13 @@ public class TelephonyManager { *

    Requires one of the following permissions: * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE}, * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the - * calling app has carrier privileges. + * calling app has carrier privileges (see {@link #hasCarrierPrivileges}. * *

    Note that this does not take into account any data restrictions that may be present on the * calling app. Such restrictions may be inspected with * {@link ConnectivityManager#getRestrictBackgroundStatus}. * * @return true if mobile data is enabled. - * - * @see #hasCarrierPrivileges */ @RequiresPermission(anyOf = { android.Manifest.permission.ACCESS_NETWORK_STATE, diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java index 946cecfa261ca7555f2c290fbaa892ac9b797254..96ff33255b5355dee1b70219ef173bc19a959fae 100644 --- a/telephony/java/android/telephony/TelephonyScanManager.java +++ b/telephony/java/android/telephony/TelephonyScanManager.java @@ -137,22 +137,31 @@ public final class TelephonyScanManager { for (int i = 0; i < parcelables.length; i++) { ci[i] = (CellInfo) parcelables[i]; } - executor.execute(() -> - callback.onResults((List) Arrays.asList(ci))); + executor.execute(() ->{ + Rlog.d(TAG, "onResults: " + ci.toString()); + callback.onResults((List) Arrays.asList(ci)); + }); } catch (Exception e) { Rlog.e(TAG, "Exception in networkscan callback onResults", e); } break; case CALLBACK_SCAN_ERROR: try { - executor.execute(() -> callback.onError(message.arg1)); + final int errorCode = message.arg1; + executor.execute(() -> { + Rlog.d(TAG, "onError: " + errorCode); + callback.onError(errorCode); + }); } catch (Exception e) { Rlog.e(TAG, "Exception in networkscan callback onError", e); } break; case CALLBACK_SCAN_COMPLETE: try { - executor.execute(() -> callback.onComplete()); + executor.execute(() -> { + Rlog.d(TAG, "onComplete"); + callback.onComplete(); + }); mScanInfo.remove(message.arg2); } catch (Exception e) { Rlog.e(TAG, "Exception in networkscan callback onComplete", e); diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java index 0c17147ca3fa4d8bf420702e67620b782a0c4729..125161d6237328646c23893a0f7304503e78e21c 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 CREATOR = new Creator() { @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/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 73a05af8e56e42ee3792fa1f5e6d3547c96df21b..145ed7eeabdd0cca1d8392c6dab8b3602fb08e0c 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -17,10 +17,10 @@ package android.telephony.data; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.StringDef; import android.content.ContentValues; import android.database.Cursor; import android.hardware.radio.V1_0.ApnTypes; +import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.provider.Telephony; @@ -28,17 +28,15 @@ import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Log; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Objects; /** @@ -46,25 +44,184 @@ import java.util.Objects; */ public class ApnSetting implements Parcelable { - static final String LOG_TAG = "ApnSetting"; + private static final String LOG_TAG = "ApnSetting"; private static final boolean VDBG = false; + private static final Map APN_TYPE_STRING_MAP; + private static final Map APN_TYPE_INT_MAP; + private static final Map PROTOCOL_STRING_MAP; + private static final Map PROTOCOL_INT_MAP; + private static final Map MVNO_TYPE_STRING_MAP; + private static final Map MVNO_TYPE_INT_MAP; + private static final int NOT_IN_MAP_INT = -1; + private static final int NO_PORT_SPECIFIED = -1; + + /** All APN types except IA. */ + private static final int TYPE_ALL_BUT_IA = ApnTypes.ALL & (~ApnTypes.IA); + + /** APN type for default data traffic and HiPri traffic. */ + public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI; + /** APN type for MMS traffic. */ + public static final int TYPE_MMS = ApnTypes.MMS; + /** APN type for SUPL assisted GPS. */ + public static final int TYPE_SUPL = ApnTypes.SUPL; + /** APN type for DUN traffic. */ + public static final int TYPE_DUN = ApnTypes.DUN; + /** APN type for HiPri traffic. */ + public static final int TYPE_HIPRI = ApnTypes.HIPRI; + /** APN type for accessing the carrier's FOTA portal, used for over the air updates. */ + public static final int TYPE_FOTA = ApnTypes.FOTA; + /** APN type for IMS. */ + public static final int TYPE_IMS = ApnTypes.IMS; + /** APN type for CBS. */ + public static final int TYPE_CBS = ApnTypes.CBS; + /** APN type for IA Initial Attach APN. */ + public static final int TYPE_IA = ApnTypes.IA; + /** + * APN type for Emergency PDN. This is not an IA apn, but is used + * for access to carrier services in an emergency call situation. + */ + public static final int TYPE_EMERGENCY = ApnTypes.EMERGENCY; + + /** @hide */ + @IntDef(flag = true, prefix = { "TYPE_" }, value = { + TYPE_DEFAULT, + TYPE_MMS, + TYPE_SUPL, + TYPE_DUN, + TYPE_HIPRI, + TYPE_FOTA, + TYPE_IMS, + TYPE_CBS, + TYPE_IA, + TYPE_EMERGENCY + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ApnType {} + + // Possible values for authentication types. + /** No authentication type. */ + public static final int AUTH_TYPE_NONE = 0; + /** Authentication type for PAP. */ + public static final int AUTH_TYPE_PAP = 1; + /** Authentication type for CHAP. */ + public static final int AUTH_TYPE_CHAP = 2; + /** Authentication type for PAP or CHAP. */ + public static final int AUTH_TYPE_PAP_OR_CHAP = 3; + + /** @hide */ + @IntDef(prefix = { "AUTH_TYPE_" }, value = { + AUTH_TYPE_NONE, + AUTH_TYPE_PAP, + AUTH_TYPE_CHAP, + AUTH_TYPE_PAP_OR_CHAP, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AuthType {} + + // Possible values for protocol. + /** Protocol type for IP. */ + public static final int PROTOCOL_IP = 0; + /** Protocol type for IPV6. */ + public static final int PROTOCOL_IPV6 = 1; + /** Protocol type for IPV4V6. */ + public static final int PROTOCOL_IPV4V6 = 2; + /** Protocol type for PPP. */ + public static final int PROTOCOL_PPP = 3; + + /** @hide */ + @IntDef(prefix = { "PROTOCOL_" }, value = { + PROTOCOL_IP, + PROTOCOL_IPV6, + PROTOCOL_IPV4V6, + PROTOCOL_PPP, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ProtocolType {} + + // Possible values for MVNO type. + /** MVNO type for service provider name. */ + public static final int MVNO_TYPE_SPN = 0; + /** MVNO type for IMSI. */ + public static final int MVNO_TYPE_IMSI = 1; + /** MVNO type for group identifier level 1. */ + public static final int MVNO_TYPE_GID = 2; + /** MVNO type for ICCID. */ + public static final int MVNO_TYPE_ICCID = 3; + + /** @hide */ + @IntDef(prefix = { "MVNO_TYPE_" }, value = { + MVNO_TYPE_SPN, + MVNO_TYPE_IMSI, + MVNO_TYPE_GID, + MVNO_TYPE_ICCID, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MvnoType {} + + static { + APN_TYPE_STRING_MAP = new ArrayMap(); + APN_TYPE_STRING_MAP.put("*", TYPE_ALL_BUT_IA); + APN_TYPE_STRING_MAP.put("default", TYPE_DEFAULT); + APN_TYPE_STRING_MAP.put("mms", TYPE_MMS); + APN_TYPE_STRING_MAP.put("supl", TYPE_SUPL); + APN_TYPE_STRING_MAP.put("dun", TYPE_DUN); + APN_TYPE_STRING_MAP.put("hipri", TYPE_HIPRI); + APN_TYPE_STRING_MAP.put("fota", TYPE_FOTA); + APN_TYPE_STRING_MAP.put("ims", TYPE_IMS); + APN_TYPE_STRING_MAP.put("cbs", TYPE_CBS); + APN_TYPE_STRING_MAP.put("ia", TYPE_IA); + APN_TYPE_STRING_MAP.put("emergency", TYPE_EMERGENCY); + APN_TYPE_INT_MAP = new ArrayMap(); + APN_TYPE_INT_MAP.put(TYPE_DEFAULT, "default"); + APN_TYPE_INT_MAP.put(TYPE_MMS, "mms"); + APN_TYPE_INT_MAP.put(TYPE_SUPL, "supl"); + APN_TYPE_INT_MAP.put(TYPE_DUN, "dun"); + APN_TYPE_INT_MAP.put(TYPE_HIPRI, "hipri"); + APN_TYPE_INT_MAP.put(TYPE_FOTA, "fota"); + APN_TYPE_INT_MAP.put(TYPE_IMS, "ims"); + APN_TYPE_INT_MAP.put(TYPE_CBS, "cbs"); + APN_TYPE_INT_MAP.put(TYPE_IA, "ia"); + APN_TYPE_INT_MAP.put(TYPE_EMERGENCY, "emergency"); + + PROTOCOL_STRING_MAP = new ArrayMap(); + PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP); + PROTOCOL_STRING_MAP.put("IPV6", PROTOCOL_IPV6); + PROTOCOL_STRING_MAP.put("IPV4V6", PROTOCOL_IPV4V6); + PROTOCOL_STRING_MAP.put("PPP", PROTOCOL_PPP); + PROTOCOL_INT_MAP = new ArrayMap(); + PROTOCOL_INT_MAP.put(PROTOCOL_IP, "IP"); + PROTOCOL_INT_MAP.put(PROTOCOL_IPV6, "IPV6"); + PROTOCOL_INT_MAP.put(PROTOCOL_IPV4V6, "IPV4V6"); + PROTOCOL_INT_MAP.put(PROTOCOL_PPP, "PPP"); + + MVNO_TYPE_STRING_MAP = new ArrayMap(); + MVNO_TYPE_STRING_MAP.put("spn", MVNO_TYPE_SPN); + MVNO_TYPE_STRING_MAP.put("imsi", MVNO_TYPE_IMSI); + MVNO_TYPE_STRING_MAP.put("gid", MVNO_TYPE_GID); + MVNO_TYPE_STRING_MAP.put("iccid", MVNO_TYPE_ICCID); + MVNO_TYPE_INT_MAP = new ArrayMap(); + MVNO_TYPE_INT_MAP.put(MVNO_TYPE_SPN, "spn"); + MVNO_TYPE_INT_MAP.put(MVNO_TYPE_IMSI, "imsi"); + MVNO_TYPE_INT_MAP.put(MVNO_TYPE_GID, "gid"); + MVNO_TYPE_INT_MAP.put(MVNO_TYPE_ICCID, "iccid"); + } + private final String mEntryName; private final String mApnName; - private final InetAddress mProxy; - private final int mPort; - private final URL mMmsc; - private final InetAddress mMmsProxy; - private final int mMmsPort; + private final InetAddress mProxyAddress; + private final int mProxyPort; + private final Uri mMmsc; + private final InetAddress mMmsProxyAddress; + private final int mMmsProxyPort; private final String mUser; private final String mPassword; private final int mAuthType; - private final List mTypes; - private final int mTypesBitmap; + private final int mApnTypeBitmask; private final int mId; private final String mOperatorNumeric; - private final String mProtocol; - private final String mRoamingProtocol; + private final int mProtocol; + private final int mRoamingProtocol; private final int mMtu; private final boolean mCarrierEnabled; @@ -78,21 +235,11 @@ public class ApnSetting implements Parcelable { private final int mWaitTime; private final int mMaxConnsTime; - private final String mMvnoType; + private final int mMvnoType; private final String mMvnoMatchData; private boolean mPermanentFailed = false; - /** - * Returns the types bitmap of the APN. - * - * @return types bitmap of the APN - * @hide - */ - public int getTypesBitmap() { - return mTypesBitmap; - } - /** * Returns the MTU size of the mobile interface to which the APN connected. * @@ -211,8 +358,8 @@ public class ApnSetting implements Parcelable { * * @return proxy address. */ - public InetAddress getProxy() { - return mProxy; + public InetAddress getProxyAddress() { + return mProxyAddress; } /** @@ -220,15 +367,15 @@ public class ApnSetting implements Parcelable { * * @return proxy port */ - public int getPort() { - return mPort; + public int getProxyPort() { + return mProxyPort; } /** - * Returns the MMSC URL of the APN. + * Returns the MMSC Uri of the APN. * - * @return MMSC URL. + * @return MMSC Uri. */ - public URL getMmsc() { + public Uri getMmsc() { return mMmsc; } @@ -237,8 +384,8 @@ public class ApnSetting implements Parcelable { * * @return MMS proxy address. */ - public InetAddress getMmsProxy() { - return mMmsProxy; + public InetAddress getMmsProxyAddress() { + return mMmsProxyAddress; } /** @@ -246,8 +393,8 @@ public class ApnSetting implements Parcelable { * * @return MMS proxy port */ - public int getMmsPort() { - return mMmsPort; + public int getMmsProxyPort() { + return mMmsProxyPort; } /** @@ -268,21 +415,9 @@ public class ApnSetting implements Parcelable { return mPassword; } - /** @hide */ - @IntDef({ - AUTH_TYPE_NONE, - AUTH_TYPE_PAP, - AUTH_TYPE_CHAP, - AUTH_TYPE_PAP_OR_CHAP, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface AuthType {} - /** * Returns the authentication type of the APN. * - * Example of possible values: {@link #AUTH_TYPE_NONE}, {@link #AUTH_TYPE_PAP}. - * * @return authentication type */ @AuthType @@ -290,32 +425,20 @@ public class ApnSetting implements Parcelable { return mAuthType; } - /** @hide */ - @StringDef({ - TYPE_DEFAULT, - TYPE_MMS, - TYPE_SUPL, - TYPE_DUN, - TYPE_HIPRI, - TYPE_FOTA, - TYPE_IMS, - TYPE_CBS, - TYPE_IA, - TYPE_EMERGENCY - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ApnType {} - /** - * Returns the list of APN types of the APN. + * Returns the bitmask of APN types. * - * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}. + *

    Apn types are usage categories for an APN entry. One APN entry may support multiple + * APN types, eg, a single APN may service regular internet traffic ("default") as well as + * MMS-specific connections. * - * @return the list of APN types + *

    The bitmask of APN types is calculated from APN types defined in {@link ApnSetting}. + * + * @see Builder#setApnTypeBitmask(int) + * @return a bitmask describing the types of the APN */ - @ApnType - public List getTypes() { - return mTypes; + public @ApnType int getApnTypeBitmask() { + return mApnTypeBitmask; } /** @@ -328,7 +451,7 @@ public class ApnSetting implements Parcelable { } /** - * Returns the numeric operator ID for the APN. Usually + * Returns the numeric operator ID for the APN. Numeric operator ID is defined as * {@link android.provider.Telephony.Carriers#MCC} + * {@link android.provider.Telephony.Carriers#MNC}. * @@ -338,37 +461,29 @@ public class ApnSetting implements Parcelable { return mOperatorNumeric; } - /** @hide */ - @StringDef({ - PROTOCOL_IP, - PROTOCOL_IPV6, - PROTOCOL_IPV4V6, - PROTOCOL_PPP, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ProtocolType {} - /** * Returns the protocol to use to connect to this APN. * - * One of the {@code PDP_type} values in TS 27.007 section 10.1.1. - * Example of possible values: {@link #PROTOCOL_IP}, {@link #PROTOCOL_IPV6}. + *

    Protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1. * + * @see Builder#setProtocol(int) * @return the protocol */ @ProtocolType - public String getProtocol() { + public int getProtocol() { return mProtocol; } /** - * Returns the protocol to use to connect to this APN when roaming. + * Returns the protocol to use to connect to this APN while the device is roaming. * - * The syntax is the same as {@link android.provider.Telephony.Carriers#PROTOCOL}. + *

    Roaming protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1. * + * @see Builder#setRoamingProtocol(int) * @return the roaming protocol */ - public String getRoamingProtocol() { + @ProtocolType + public int getRoamingProtocol() { return mRoamingProtocol; } @@ -398,41 +513,29 @@ public class ApnSetting implements Parcelable { return mNetworkTypeBitmask; } - /** @hide */ - @StringDef({ - MVNO_TYPE_SPN, - MVNO_TYPE_IMSI, - MVNO_TYPE_GID, - MVNO_TYPE_ICCID, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface MvnoType {} - /** * Returns the MVNO match type for this APN. * - * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}. - * + * @see Builder#setMvnoType(int) * @return the MVNO match type */ @MvnoType - public String getMvnoType() { + public int getMvnoType() { return mMvnoType; } private ApnSetting(Builder builder) { this.mEntryName = builder.mEntryName; this.mApnName = builder.mApnName; - this.mProxy = builder.mProxy; - this.mPort = builder.mPort; + this.mProxyAddress = builder.mProxyAddress; + this.mProxyPort = builder.mProxyPort; this.mMmsc = builder.mMmsc; - this.mMmsProxy = builder.mMmsProxy; - this.mMmsPort = builder.mMmsPort; + this.mMmsProxyAddress = builder.mMmsProxyAddress; + this.mMmsProxyPort = builder.mMmsProxyPort; this.mUser = builder.mUser; this.mPassword = builder.mPassword; this.mAuthType = builder.mAuthType; - this.mTypes = (builder.mTypes == null ? new ArrayList() : builder.mTypes); - this.mTypesBitmap = builder.mTypesBitmap; + this.mApnTypeBitmask = builder.mApnTypeBitmask; this.mId = builder.mId; this.mOperatorNumeric = builder.mOperatorNumeric; this.mProtocol = builder.mProtocol; @@ -451,25 +554,25 @@ public class ApnSetting implements Parcelable { /** @hide */ public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName, - String apnName, InetAddress proxy, int port, URL mmsc, InetAddress mmsProxy, - int mmsPort, String user, String password, int authType, List types, - String protocol, String roamingProtocol, boolean carrierEnabled, + String apnName, InetAddress proxy, int port, Uri mmsc, InetAddress mmsProxy, + int mmsPort, String user, String password, int authType, int mApnTypeBitmask, + int protocol, int roamingProtocol, boolean carrierEnabled, int networkTypeBitmask, int profileId, boolean modemCognitive, int maxConns, - int waitTime, int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) { + int waitTime, int maxConnsTime, int mtu, int mvnoType, String mvnoMatchData) { return new Builder() .setId(id) .setOperatorNumeric(operatorNumeric) .setEntryName(entryName) .setApnName(apnName) - .setProxy(proxy) - .setPort(port) + .setProxyAddress(proxy) + .setProxyPort(port) .setMmsc(mmsc) - .setMmsProxy(mmsProxy) - .setMmsPort(mmsPort) + .setMmsProxyAddress(mmsProxy) + .setMmsProxyPort(mmsPort) .setUser(user) .setPassword(password) .setAuthType(authType) - .setTypes(types) + .setApnTypeBitmask(mApnTypeBitmask) .setProtocol(protocol) .setRoamingProtocol(roamingProtocol) .setCarrierEnabled(carrierEnabled) @@ -487,7 +590,7 @@ public class ApnSetting implements Parcelable { /** @hide */ public static ApnSetting makeApnSetting(Cursor cursor) { - String[] types = parseTypes( + final int apnTypesBitmask = parseTypes( cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); int networkTypeBitmask = cursor.getInt( cursor.getColumnIndexOrThrow(Telephony.Carriers.NETWORK_TYPE_BITMASK)); @@ -507,7 +610,7 @@ public class ApnSetting implements Parcelable { cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))), portFromString(cursor.getString( cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))), - URLFromString(cursor.getString( + UriFromString(cursor.getString( cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), inetAddressFromString(cursor.getString( cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))), @@ -516,10 +619,12 @@ public class ApnSetting implements Parcelable { cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), - Arrays.asList(types), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)), - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.ROAMING_PROTOCOL)), + apnTypesBitmask, + nullToNotInMapInt(PROTOCOL_STRING_MAP.get( + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)))), + nullToNotInMapInt(PROTOCOL_STRING_MAP.get( + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.ROAMING_PROTOCOL)))), cursor.getInt(cursor.getColumnIndexOrThrow( Telephony.Carriers.CARRIER_ENABLED)) == 1, networkTypeBitmask, @@ -531,8 +636,9 @@ public class ApnSetting implements Parcelable { cursor.getInt(cursor.getColumnIndexOrThrow( Telephony.Carriers.MAX_CONNS_TIME)), cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MVNO_TYPE)), + nullToNotInMapInt(MVNO_TYPE_STRING_MAP.get( + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_TYPE)))), cursor.getString(cursor.getColumnIndexOrThrow( Telephony.Carriers.MVNO_MATCH_DATA))); } @@ -540,8 +646,8 @@ public class ApnSetting implements Parcelable { /** @hide */ public static ApnSetting makeApnSetting(ApnSetting apn) { return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName, - apn.mProxy, apn.mPort, apn.mMmsc, apn.mMmsProxy, apn.mMmsPort, apn.mUser, - apn.mPassword, apn.mAuthType, apn.mTypes, apn.mProtocol, apn.mRoamingProtocol, + apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress, apn.mMmsProxyPort, apn.mUser, + apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask, apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask, apn.mProfileId, apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime, apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData); @@ -555,18 +661,14 @@ public class ApnSetting implements Parcelable { .append(", ").append(mId) .append(", ").append(mOperatorNumeric) .append(", ").append(mApnName) - .append(", ").append(inetAddressToString(mProxy)) - .append(", ").append(URLToString(mMmsc)) - .append(", ").append(inetAddressToString(mMmsProxy)) - .append(", ").append(portToString(mMmsPort)) - .append(", ").append(portToString(mPort)) + .append(", ").append(inetAddressToString(mProxyAddress)) + .append(", ").append(UriToString(mMmsc)) + .append(", ").append(inetAddressToString(mMmsProxyAddress)) + .append(", ").append(portToString(mMmsProxyPort)) + .append(", ").append(portToString(mProxyPort)) .append(", ").append(mAuthType).append(", "); - for (int i = 0; i < mTypes.size(); i++) { - sb.append(mTypes.get(i)); - if (i < mTypes.size() - 1) { - sb.append(" | "); - } - } + final String[] types = deParseTypes(mApnTypeBitmask).split(","); + sb.append(TextUtils.join(" | ", types)).append(", "); sb.append(", ").append(mProtocol); sb.append(", ").append(mRoamingProtocol); sb.append(", ").append(mCarrierEnabled); @@ -588,56 +690,37 @@ public class ApnSetting implements Parcelable { * @hide */ public boolean hasMvnoParams() { - return !TextUtils.isEmpty(mMvnoType) && !TextUtils.isEmpty(mMvnoMatchData); + return (mMvnoType != NOT_IN_MAP_INT) && !TextUtils.isEmpty(mMvnoMatchData); } /** @hide */ - public boolean canHandleType(String type) { - if (!mCarrierEnabled) return false; - boolean wildcardable = true; - if (TYPE_IA.equalsIgnoreCase(type)) wildcardable = false; - for (String t : mTypes) { - // DEFAULT handles all, and HIPRI is handled by DEFAULT - if (t.equalsIgnoreCase(type) - || (wildcardable && t.equalsIgnoreCase(TYPE_ALL)) - || (t.equalsIgnoreCase(TYPE_DEFAULT) - && type.equalsIgnoreCase(TYPE_HIPRI))) { - return true; - } - } - return false; + public boolean canHandleType(@ApnType int type) { + return mCarrierEnabled && ((mApnTypeBitmask & type) == type); } // check whether the types of two APN same (even only one type of each APN is same) private boolean typeSameAny(ApnSetting first, ApnSetting second) { if (VDBG) { StringBuilder apnType1 = new StringBuilder(first.mApnName + ": "); - for (int index1 = 0; index1 < first.mTypes.size(); index1++) { - apnType1.append(first.mTypes.get(index1)); - apnType1.append(","); - } + apnType1.append(deParseTypes(first.mApnTypeBitmask)); StringBuilder apnType2 = new StringBuilder(second.mApnName + ": "); - for (int index1 = 0; index1 < second.mTypes.size(); index1++) { - apnType2.append(second.mTypes.get(index1)); - apnType2.append(","); - } + apnType2.append(deParseTypes(second.mApnTypeBitmask)); + Rlog.d(LOG_TAG, "APN1: is " + apnType1); Rlog.d(LOG_TAG, "APN2: is " + apnType2); } - for (int index1 = 0; index1 < first.mTypes.size(); index1++) { - for (int index2 = 0; index2 < second.mTypes.size(); index2++) { - if (first.mTypes.get(index1).equals(ApnSetting.TYPE_ALL) - || second.mTypes.get(index2).equals(ApnSetting.TYPE_ALL) - || first.mTypes.get(index1).equals(second.mTypes.get(index2))) { - if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return true"); - return true; - } + if ((first.mApnTypeBitmask & second.mApnTypeBitmask) != 0) { + if (VDBG) { + Rlog.d(LOG_TAG, "typeSameAny: return true"); } + return true; } - if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return false"); + if (VDBG) { + Rlog.d(LOG_TAG, "typeSameAny: return false"); + } return false; } @@ -655,16 +738,15 @@ public class ApnSetting implements Parcelable { && Objects.equals(mId, other.mId) && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) && Objects.equals(mApnName, other.mApnName) - && Objects.equals(mProxy, other.mProxy) + && Objects.equals(mProxyAddress, other.mProxyAddress) && Objects.equals(mMmsc, other.mMmsc) - && Objects.equals(mMmsProxy, other.mMmsProxy) - && Objects.equals(mMmsPort, other.mMmsPort) - && Objects.equals(mPort,other.mPort) + && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) + && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) + && Objects.equals(mProxyPort,other.mProxyPort) && Objects.equals(mUser, other.mUser) && Objects.equals(mPassword, other.mPassword) && Objects.equals(mAuthType, other.mAuthType) - && Objects.equals(mTypes, other.mTypes) - && Objects.equals(mTypesBitmap, other.mTypesBitmap) + && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) && Objects.equals(mProtocol, other.mProtocol) && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) @@ -701,16 +783,15 @@ public class ApnSetting implements Parcelable { return mEntryName.equals(other.mEntryName) && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) && Objects.equals(mApnName, other.mApnName) - && Objects.equals(mProxy, other.mProxy) + && Objects.equals(mProxyAddress, other.mProxyAddress) && Objects.equals(mMmsc, other.mMmsc) - && Objects.equals(mMmsProxy, other.mMmsProxy) - && Objects.equals(mMmsPort, other.mMmsPort) - && Objects.equals(mPort, other.mPort) + && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) + && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) + && Objects.equals(mProxyPort, other.mProxyPort) && Objects.equals(mUser, other.mUser) && Objects.equals(mPassword, other.mPassword) && Objects.equals(mAuthType, other.mAuthType) - && Objects.equals(mTypes, other.mTypes) - && Objects.equals(mTypesBitmap, other.mTypesBitmap) + && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) && (isDataRoaming || Objects.equals(mProtocol,other.mProtocol)) && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) @@ -736,17 +817,17 @@ public class ApnSetting implements Parcelable { && !other.canHandleType(TYPE_DUN) && Objects.equals(this.mApnName, other.mApnName) && !typeSameAny(this, other) - && xorEqualsInetAddress(this.mProxy, other.mProxy) - && xorEqualsPort(this.mPort, other.mPort) + && xorEquals(this.mProxyAddress, other.mProxyAddress) + && xorEqualsPort(this.mProxyPort, other.mProxyPort) && xorEquals(this.mProtocol, other.mProtocol) && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol) && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled) && Objects.equals(this.mProfileId, other.mProfileId) && Objects.equals(this.mMvnoType, other.mMvnoType) && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData) - && xorEqualsURL(this.mMmsc, other.mMmsc) - && xorEqualsInetAddress(this.mMmsProxy, other.mMmsProxy) - && xorEqualsPort(this.mMmsPort, other.mMmsPort)) + && xorEquals(this.mMmsc, other.mMmsc) + && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress) + && xorEqualsPort(this.mMmsProxyPort, other.mMmsProxyPort)) && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask); } @@ -757,42 +838,23 @@ public class ApnSetting implements Parcelable { || TextUtils.isEmpty(second)); } - // Equal or one is not specified. - private boolean xorEqualsInetAddress(InetAddress first, InetAddress second) { - return first == null || second == null || first.equals(second); - } - - // Equal or one is not specified. - private boolean xorEqualsURL(URL first, URL second) { + // Equal or one is not null. + private boolean xorEquals(Object first, Object second) { return first == null || second == null || first.equals(second); } // Equal or one is not specified. private boolean xorEqualsPort(int first, int second) { - return first == -1 || second == -1 || Objects.equals(first, second); - } - - // Helper function to convert APN string into a 32-bit bitmask. - private static int getApnBitmask(String apn) { - switch (apn) { - case TYPE_DEFAULT: return ApnTypes.DEFAULT; - case TYPE_MMS: return ApnTypes.MMS; - case TYPE_SUPL: return ApnTypes.SUPL; - case TYPE_DUN: return ApnTypes.DUN; - case TYPE_HIPRI: return ApnTypes.HIPRI; - case TYPE_FOTA: return ApnTypes.FOTA; - case TYPE_IMS: return ApnTypes.IMS; - case TYPE_CBS: return ApnTypes.CBS; - case TYPE_IA: return ApnTypes.IA; - case TYPE_EMERGENCY: return ApnTypes.EMERGENCY; - case TYPE_ALL: return ApnTypes.ALL; - default: return ApnTypes.NONE; - } + return first == NO_PORT_SPECIFIED || second == NO_PORT_SPECIFIED + || Objects.equals(first, second); } - private String deParseTypes(List types) { - if (types == null) { - return null; + private String deParseTypes(int apnTypeBitmask) { + List types = new ArrayList<>(); + for (Integer type : APN_TYPE_INT_MAP.keySet()) { + if ((apnTypeBitmask & type) == type) { + types.add(APN_TYPE_INT_MAP.get(type)); + } } return TextUtils.join(",", types); } @@ -808,21 +870,25 @@ public class ApnSetting implements Parcelable { apnValue.put(Telephony.Carriers.NUMERIC, nullToEmpty(mOperatorNumeric)); apnValue.put(Telephony.Carriers.NAME, nullToEmpty(mEntryName)); apnValue.put(Telephony.Carriers.APN, nullToEmpty(mApnName)); - apnValue.put(Telephony.Carriers.PROXY, mProxy == null ? "" : inetAddressToString(mProxy)); - apnValue.put(Telephony.Carriers.PORT, portToString(mPort)); - apnValue.put(Telephony.Carriers.MMSC, mMmsc == null ? "" : URLToString(mMmsc)); - apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsPort)); - apnValue.put(Telephony.Carriers.MMSPROXY, mMmsProxy == null - ? "" : inetAddressToString(mMmsProxy)); + apnValue.put(Telephony.Carriers.PROXY, mProxyAddress == null ? "" + : inetAddressToString(mProxyAddress)); + apnValue.put(Telephony.Carriers.PORT, portToString(mProxyPort)); + apnValue.put(Telephony.Carriers.MMSC, mMmsc == null ? "" : UriToString(mMmsc)); + apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsProxyPort)); + apnValue.put(Telephony.Carriers.MMSPROXY, mMmsProxyAddress == null + ? "" : inetAddressToString(mMmsProxyAddress)); apnValue.put(Telephony.Carriers.USER, nullToEmpty(mUser)); apnValue.put(Telephony.Carriers.PASSWORD, nullToEmpty(mPassword)); apnValue.put(Telephony.Carriers.AUTH_TYPE, mAuthType); - String apnType = deParseTypes(mTypes); + String apnType = deParseTypes(mApnTypeBitmask); apnValue.put(Telephony.Carriers.TYPE, nullToEmpty(apnType)); - apnValue.put(Telephony.Carriers.PROTOCOL, nullToEmpty(mProtocol)); - apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL, nullToEmpty(mRoamingProtocol)); + apnValue.put(Telephony.Carriers.PROTOCOL, + nullToEmpty(PROTOCOL_INT_MAP.get(mProtocol))); + apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL, + nullToEmpty(PROTOCOL_INT_MAP.get(mRoamingProtocol))); apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled); - apnValue.put(Telephony.Carriers.MVNO_TYPE, nullToEmpty(mMvnoType)); + apnValue.put(Telephony.Carriers.MVNO_TYPE, + nullToEmpty(MVNO_TYPE_INT_MAP.get(mMvnoType))); apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask); return apnValue; @@ -830,32 +896,31 @@ public class ApnSetting implements Parcelable { /** * @param types comma delimited list of APN types - * @return array of APN types + * @return bitmask of APN types * @hide */ - public static String[] parseTypes(String types) { - String[] result; - // If unset, set to DEFAULT. + public static int parseTypes(String types) { + // If unset, set to ALL. if (TextUtils.isEmpty(types)) { - result = new String[1]; - result[0] = TYPE_ALL; + return TYPE_ALL_BUT_IA; } else { - result = types.split(","); + int result = 0; + for (String str : types.split(",")) { + Integer type = APN_TYPE_STRING_MAP.get(str); + if (type != null) { + result |= type; + } + } + return result; } - return result; } - private static URL URLFromString(String url) { - try { - return TextUtils.isEmpty(url) ? null : new URL(url); - } catch (MalformedURLException e) { - Log.e(LOG_TAG, "Can't parse URL from string."); - return null; - } + private static Uri UriFromString(String uri) { + return TextUtils.isEmpty(uri) ? null : Uri.parse(uri); } - private static String URLToString(URL url) { - return url == null ? "" : url.toString(); + private static String UriToString(Uri uri) { + return uri == null ? "" : uri.toString(); } private static InetAddress inetAddressFromString(String inetAddress) { @@ -887,7 +952,7 @@ public class ApnSetting implements Parcelable { } private static int portFromString(String strPort) { - int port = -1; + int port = NO_PORT_SPECIFIED; if (!TextUtils.isEmpty(strPort)) { try { port = Integer.parseInt(strPort); @@ -899,7 +964,7 @@ public class ApnSetting implements Parcelable { } private static String portToString(int port) { - return port == -1 ? "" : Integer.toString(port); + return port == NO_PORT_SPECIFIED ? "" : Integer.toString(port); } // Implement Parcelable. @@ -916,19 +981,19 @@ public class ApnSetting implements Parcelable { dest.writeString(mOperatorNumeric); dest.writeString(mEntryName); dest.writeString(mApnName); - dest.writeValue(mProxy); - dest.writeInt(mPort); + dest.writeValue(mProxyAddress); + dest.writeInt(mProxyPort); dest.writeValue(mMmsc); - dest.writeValue(mMmsProxy); - dest.writeInt(mMmsPort); + dest.writeValue(mMmsProxyAddress); + dest.writeInt(mMmsProxyPort); dest.writeString(mUser); dest.writeString(mPassword); dest.writeInt(mAuthType); - dest.writeStringArray(mTypes.toArray(new String[0])); - dest.writeString(mProtocol); - dest.writeString(mRoamingProtocol); + dest.writeInt(mApnTypeBitmask); + dest.writeInt(mProtocol); + dest.writeInt(mRoamingProtocol); dest.writeInt(mCarrierEnabled ? 1: 0); - dest.writeString(mMvnoType); + dest.writeInt(mMvnoType); dest.writeInt(mNetworkTypeBitmask); } @@ -939,23 +1004,23 @@ public class ApnSetting implements Parcelable { final String apnName = in.readString(); final InetAddress proxy = (InetAddress)in.readValue(InetAddress.class.getClassLoader()); final int port = in.readInt(); - final URL mmsc = (URL)in.readValue(URL.class.getClassLoader()); + final Uri mmsc = (Uri)in.readValue(Uri.class.getClassLoader()); final InetAddress mmsProxy = (InetAddress)in.readValue(InetAddress.class.getClassLoader()); final int mmsPort = in.readInt(); final String user = in.readString(); final String password = in.readString(); final int authType = in.readInt(); - final List types = Arrays.asList(in.readStringArray()); - final String protocol = in.readString(); - final String roamingProtocol = in.readString(); + final int apnTypesBitmask = in.readInt(); + final int protocol = in.readInt(); + final int roamingProtocol = in.readInt(); final boolean carrierEnabled = in.readInt() > 0; - final String mvnoType = in.readString(); + final int mvnoType = in.readInt(); final int networkTypeBitmask = in.readInt(); return makeApnSetting(id, operatorNumeric, entryName, apnName, - proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, types, protocol, - roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false, - 0, 0, 0, 0, mvnoType, null); + proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, apnTypesBitmask, + protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false, + 0, 0, 0, 0, mvnoType, null); } public static final Parcelable.Creator CREATOR = @@ -971,89 +1036,26 @@ public class ApnSetting implements Parcelable { } }; - /** - * APN types for data connections. These are usage categories for an APN - * entry. One APN entry may support multiple APN types, eg, a single APN - * may service regular internet traffic ("default") as well as MMS-specific - * connections.
    - * ALL is a special type to indicate that this APN entry can - * service all data connections. - */ - public static final String TYPE_ALL = "*"; - /** APN type for default data traffic */ - public static final String TYPE_DEFAULT = "default"; - /** APN type for MMS traffic */ - public static final String TYPE_MMS = "mms"; - /** APN type for SUPL assisted GPS */ - public static final String TYPE_SUPL = "supl"; - /** APN type for DUN traffic */ - public static final String TYPE_DUN = "dun"; - /** APN type for HiPri traffic */ - public static final String TYPE_HIPRI = "hipri"; - /** APN type for FOTA */ - public static final String TYPE_FOTA = "fota"; - /** APN type for IMS */ - public static final String TYPE_IMS = "ims"; - /** APN type for CBS */ - public static final String TYPE_CBS = "cbs"; - /** APN type for IA Initial Attach APN */ - public static final String TYPE_IA = "ia"; - /** APN type for Emergency PDN. This is not an IA apn, but is used - * for access to carrier services in an emergency call situation. */ - public static final String TYPE_EMERGENCY = "emergency"; - /** - * Array of all APN types - * - * @hide - */ - public static final String[] ALL_TYPES = { - TYPE_DEFAULT, - TYPE_MMS, - TYPE_SUPL, - TYPE_DUN, - TYPE_HIPRI, - TYPE_FOTA, - TYPE_IMS, - TYPE_CBS, - TYPE_IA, - TYPE_EMERGENCY - }; - - // Possible values for authentication types. - public static final int AUTH_TYPE_NONE = 0; - public static final int AUTH_TYPE_PAP = 1; - public static final int AUTH_TYPE_CHAP = 2; - public static final int AUTH_TYPE_PAP_OR_CHAP = 3; - - // Possible values for protocol. - public static final String PROTOCOL_IP = "IP"; - public static final String PROTOCOL_IPV6 = "IPV6"; - public static final String PROTOCOL_IPV4V6 = "IPV4V6"; - public static final String PROTOCOL_PPP = "PPP"; - - // Possible values for MVNO type. - public static final String MVNO_TYPE_SPN = "spn"; - public static final String MVNO_TYPE_IMSI = "imsi"; - public static final String MVNO_TYPE_GID = "gid"; - public static final String MVNO_TYPE_ICCID = "iccid"; + private static int nullToNotInMapInt(Integer value) { + return value == null ? NOT_IN_MAP_INT : value; + } public static class Builder{ private String mEntryName; private String mApnName; - private InetAddress mProxy; - private int mPort = -1; - private URL mMmsc; - private InetAddress mMmsProxy; - private int mMmsPort = -1; + private InetAddress mProxyAddress; + private int mProxyPort = NO_PORT_SPECIFIED; + private Uri mMmsc; + private InetAddress mMmsProxyAddress; + private int mMmsProxyPort = NO_PORT_SPECIFIED; private String mUser; private String mPassword; private int mAuthType; - private List mTypes; - private int mTypesBitmap; + private int mApnTypeBitmask; private int mId; private String mOperatorNumeric; - private String mProtocol; - private String mRoamingProtocol; + private int mProtocol = NOT_IN_MAP_INT; + private int mRoamingProtocol = NOT_IN_MAP_INT; private int mMtu; private int mNetworkTypeBitmask; private boolean mCarrierEnabled; @@ -1062,7 +1064,7 @@ public class ApnSetting implements Parcelable { private int mMaxConns; private int mWaitTime; private int mMaxConnsTime; - private String mMvnoType; + private int mMvnoType = NOT_IN_MAP_INT; private String mMvnoMatchData; /** @@ -1182,8 +1184,8 @@ public class ApnSetting implements Parcelable { * * @param proxy the proxy address to set for the APN */ - public Builder setProxy(InetAddress proxy) { - this.mProxy = proxy; + public Builder setProxyAddress(InetAddress proxy) { + this.mProxyAddress = proxy; return this; } @@ -1192,17 +1194,17 @@ public class ApnSetting implements Parcelable { * * @param port the proxy port to set for the APN */ - public Builder setPort(int port) { - this.mPort = port; + public Builder setProxyPort(int port) { + this.mProxyPort = port; return this; } /** - * Sets the MMSC URL of the APN. + * Sets the MMSC Uri of the APN. * - * @param mmsc the MMSC URL to set for the APN + * @param mmsc the MMSC Uri to set for the APN */ - public Builder setMmsc(URL mmsc) { + public Builder setMmsc(Uri mmsc) { this.mMmsc = mmsc; return this; } @@ -1212,8 +1214,8 @@ public class ApnSetting implements Parcelable { * * @param mmsProxy the MMS proxy address to set for the APN */ - public Builder setMmsProxy(InetAddress mmsProxy) { - this.mMmsProxy = mmsProxy; + public Builder setMmsProxyAddress(InetAddress mmsProxy) { + this.mMmsProxyAddress = mmsProxy; return this; } @@ -1222,8 +1224,8 @@ public class ApnSetting implements Parcelable { * * @param mmsPort the MMS proxy port to set for the APN */ - public Builder setMmsPort(int mmsPort) { - this.mMmsPort = mmsPort; + public Builder setMmsProxyPort(int mmsPort) { + this.mMmsProxyPort = mmsPort; return this; } @@ -1251,8 +1253,6 @@ public class ApnSetting implements Parcelable { /** * Sets the authentication type of the APN. * - * Example of possible values: {@link #AUTH_TYPE_NONE}, {@link #AUTH_TYPE_PAP}. - * * @param authType the authentication type to set for the APN */ public Builder setAuthType(@AuthType int authType) { @@ -1261,25 +1261,25 @@ public class ApnSetting implements Parcelable { } /** - * Sets the list of APN types of the APN. + * Sets the bitmask of APN types. + * + *

    Apn types are usage categories for an APN entry. One APN entry may support multiple + * APN types, eg, a single APN may service regular internet traffic ("default") as well as + * MMS-specific connections. * - * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}. + *

    The bitmask of APN types is calculated from APN types defined in {@link ApnSetting}. * - * @param types the list of APN types to set for the APN + * @param apnTypeBitmask a bitmask describing the types of the APN */ - public Builder setTypes(@ApnType List types) { - this.mTypes = types; - int apnBitmap = 0; - for (int i = 0; i < mTypes.size(); i++) { - mTypes.set(i, mTypes.get(i).toLowerCase()); - apnBitmap |= getApnBitmask(mTypes.get(i)); - } - this.mTypesBitmap = apnBitmap; + public Builder setApnTypeBitmask(@ApnType int apnTypeBitmask) { + this.mApnTypeBitmask = apnTypeBitmask; return this; } /** - * Set the numeric operator ID for the APN. + * Sets the numeric operator ID for the APN. Numeric operator ID is defined as + * {@link android.provider.Telephony.Carriers#MCC} + + * {@link android.provider.Telephony.Carriers#MNC}. * * @param operatorNumeric the numeric operator ID to set for this entry */ @@ -1291,22 +1291,23 @@ public class ApnSetting implements Parcelable { /** * Sets the protocol to use to connect to this APN. * - * One of the {@code PDP_type} values in TS 27.007 section 10.1.1. - * Example of possible values: {@link #PROTOCOL_IP}, {@link #PROTOCOL_IPV6}. + *

    Protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1. * * @param protocol the protocol to set to use to connect to this APN */ - public Builder setProtocol(@ProtocolType String protocol) { + public Builder setProtocol(@ProtocolType int protocol) { this.mProtocol = protocol; return this; } /** - * Sets the protocol to use to connect to this APN when roaming. + * Sets the protocol to use to connect to this APN when the device is roaming. + * + *

    Roaming protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1. * * @param roamingProtocol the protocol to set to use to connect to this APN when roaming */ - public Builder setRoamingProtocol(String roamingProtocol) { + public Builder setRoamingProtocol(@ProtocolType int roamingProtocol) { this.mRoamingProtocol = roamingProtocol; return this; } @@ -1334,16 +1335,25 @@ public class ApnSetting implements Parcelable { /** * Sets the MVNO match type for this APN. * - * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}. - * * @param mvnoType the MVNO match type to set for this APN */ - public Builder setMvnoType(@MvnoType String mvnoType) { + public Builder setMvnoType(@MvnoType int mvnoType) { this.mMvnoType = mvnoType; return this; } + /** + * Builds {@link ApnSetting} from this builder. + * + * @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)} + * is empty, or {@link #setApnTypeBitmask(int)} doesn't contain a valid bit, + * {@link ApnSetting} built from this builder otherwise. + */ public ApnSetting build() { + if ((mApnTypeBitmask & ApnTypes.ALL) == 0 || TextUtils.isEmpty(mApnName) + || TextUtils.isEmpty(mEntryName)) { + return null; + } return new ApnSetting(this); } } diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index 1637c55c0adfee3220fdf63c7da72e3d0cd63934..dff1c6fe35f6049a17712f6684f950ecf3ff21a4 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -15,11 +15,12 @@ */ package android.telephony.euicc; +import android.Manifest; import android.annotation.IntDef; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SystemApi; -import android.annotation.TestApi; import android.app.Activity; import android.app.PendingIntent; import android.content.Context; @@ -73,6 +74,7 @@ public class EuiccManager { */ @SystemApi @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public static final String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED"; @@ -301,6 +303,7 @@ public class EuiccManager { * @hide */ @SystemApi + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus() { if (!isEnabled()) { return EUICC_OTA_STATUS_UNAVAILABLE; @@ -325,6 +328,7 @@ public class EuiccManager { * @param switchAfterDownload if true, the profile will be activated upon successful download. * @param callbackIntent a PendingIntent to launch when the operation completes. */ + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void downloadSubscription(DownloadableSubscription subscription, boolean switchAfterDownload, PendingIntent callbackIntent) { if (!isEnabled()) { @@ -387,6 +391,7 @@ public class EuiccManager { * @hide */ @SystemApi + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) { if (!isEnabled()) { PendingIntent callbackIntent = @@ -422,6 +427,7 @@ public class EuiccManager { * @hide */ @SystemApi + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDownloadableSubscriptionMetadata( DownloadableSubscription subscription, PendingIntent callbackIntent) { if (!isEnabled()) { @@ -452,6 +458,7 @@ public class EuiccManager { * @hide */ @SystemApi + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) { if (!isEnabled()) { sendUnavailableError(callbackIntent); @@ -496,6 +503,7 @@ public class EuiccManager { * @param subscriptionId the ID of the subscription to delete. * @param callbackIntent a PendingIntent to launch when the operation completes. */ + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) { if (!isEnabled()) { sendUnavailableError(callbackIntent); @@ -523,6 +531,7 @@ public class EuiccManager { * current profile without activating another profile to replace it. * @param callbackIntent a PendingIntent to launch when the operation completes. */ + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) { if (!isEnabled()) { sendUnavailableError(callbackIntent); @@ -548,6 +557,7 @@ public class EuiccManager { * @param callbackIntent a PendingIntent to launch when the operation completes. * @hide */ + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void updateSubscriptionNickname( int subscriptionId, String nickname, PendingIntent callbackIntent) { if (!isEnabled()) { @@ -566,12 +576,13 @@ public class EuiccManager { * Erase all subscriptions and reset the eUICC. * *

    Requires that the calling app has the - * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for - * internal system use only. + * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. * * @param callbackIntent a PendingIntent to launch when the operation completes. * @hide */ + @SystemApi + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(PendingIntent callbackIntent) { if (!isEnabled()) { sendUnavailableError(callbackIntent); diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 27e5f943982b0901f390ca84b0c197e888b6d8a5..350dfe3a8d083d5ab546537e7bf44da44fb3bc34 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -296,7 +296,10 @@ public final class ImsCallProfile implements Parcelable { readFromParcel(in); } - /** @hide */ + /** + * Default Constructor that initializes the call profile with service type + * {@link #SERVICE_TYPE_NORMAL} and call type {@link #CALL_TYPE_VIDEO_N_VOICE} + */ public ImsCallProfile() { mServiceType = SERVICE_TYPE_NORMAL; mCallType = CALL_TYPE_VOICE_N_VIDEO; @@ -304,7 +307,25 @@ public final class ImsCallProfile implements Parcelable { mMediaProfile = new ImsStreamMediaProfile(); } - /** @hide */ + /** + * Constructor. + * + * @param serviceType the service type for the call. Can be one of the following: + * {@link #SERVICE_TYPE_NONE}, + * {@link #SERVICE_TYPE_NORMAL}, + * {@link #SERVICE_TYPE_EMERGENCY} + * @param callType the call type. Can be one of the following: + * {@link #CALL_TYPE_VOICE_N_VIDEO}, + * {@link #CALL_TYPE_VOICE}, + * {@link #CALL_TYPE_VIDEO_N_VOICE}, + * {@link #CALL_TYPE_VT}, + * {@link #CALL_TYPE_VT_TX}, + * {@link #CALL_TYPE_VT_RX}, + * {@link #CALL_TYPE_VT_NODIR}, + * {@link #CALL_TYPE_VS}, + * {@link #CALL_TYPE_VS_TX}, + * {@link #CALL_TYPE_VS_RX} + */ public ImsCallProfile(int serviceType, int callType) { mServiceType = serviceType; mCallType = callType; @@ -312,6 +333,35 @@ public final class ImsCallProfile implements Parcelable { mMediaProfile = new ImsStreamMediaProfile(); } + /** + * Constructor. + * + * @param serviceType the service type for the call. Can be one of the following: + * {@link #SERVICE_TYPE_NONE}, + * {@link #SERVICE_TYPE_NORMAL}, + * {@link #SERVICE_TYPE_EMERGENCY} + * @param callType the call type. Can be one of the following: + * {@link #CALL_TYPE_VOICE_N_VIDEO}, + * {@link #CALL_TYPE_VOICE}, + * {@link #CALL_TYPE_VIDEO_N_VOICE}, + * {@link #CALL_TYPE_VT}, + * {@link #CALL_TYPE_VT_TX}, + * {@link #CALL_TYPE_VT_RX}, + * {@link #CALL_TYPE_VT_NODIR}, + * {@link #CALL_TYPE_VS}, + * {@link #CALL_TYPE_VS_TX}, + * {@link #CALL_TYPE_VS_RX} + * @param callExtras A bundle with the call extras. + * @param mediaProfile The IMS stream media profile. + */ + public ImsCallProfile(int serviceType, int callType, Bundle callExtras, + ImsStreamMediaProfile mediaProfile) { + mServiceType = serviceType; + mCallType = callType; + mCallExtras = callExtras; + mMediaProfile = mediaProfile; + } + public String getCallExtra(String name) { return getCallExtra(name, ""); } @@ -375,6 +425,16 @@ public final class ImsCallProfile implements Parcelable { mCallExtras = (Bundle) profile.mCallExtras.clone(); } + /** + * Updates the media profile for the call. + * + * @param profile Call profile with new media profile. + */ + public void updateMediaProfile(ImsCallProfile profile) { + mMediaProfile = profile.mMediaProfile; + } + + @Override public String toString() { return "{ serviceType=" + mServiceType + diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index 2748cb5470bfa42cac14b3e0db928596a00199b2..c008711ff236670111f9489e310ebbfc6880cac6 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -160,11 +160,6 @@ public class ImsService extends Service { ImsService.this.readyForFeatureCreation(); } - @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); @@ -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 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/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java index 243352bdd180d59aa00291bd9bcd9eb2c195d0c8..137106a011b0efb70f9fb01efb206334a4929e88 100644 --- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java +++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java @@ -99,6 +99,62 @@ public final class ImsStreamMediaProfile implements Parcelable { readFromParcel(in); } + /** + * Constructor. + * + * @param audioQuality The audio quality. Can be one of the following: + * {@link #AUDIO_QUALITY_AMR}, + * {@link #AUDIO_QUALITY_AMR_WB}, + * {@link #AUDIO_QUALITY_QCELP13K}, + * {@link #AUDIO_QUALITY_EVRC}, + * {@link #AUDIO_QUALITY_EVRC_B}, + * {@link #AUDIO_QUALITY_EVRC_WB}, + * {@link #AUDIO_QUALITY_EVRC_NW}, + * {@link #AUDIO_QUALITY_GSM_EFR}, + * {@link #AUDIO_QUALITY_GSM_FR}, + * {@link #AUDIO_QUALITY_GSM_HR}, + * {@link #AUDIO_QUALITY_G711U}, + * {@link #AUDIO_QUALITY_G723}, + * {@link #AUDIO_QUALITY_G711A}, + * {@link #AUDIO_QUALITY_G722}, + * {@link #AUDIO_QUALITY_G711AB}, + * {@link #AUDIO_QUALITY_G729}, + * {@link #AUDIO_QUALITY_EVS_NB}, + * {@link #AUDIO_QUALITY_EVS_WB}, + * {@link #AUDIO_QUALITY_EVS_SWB}, + * {@link #AUDIO_QUALITY_EVS_FB}, + * @param audioDirection The audio direction. Can be one of the following: + * {@link #DIRECTION_INVALID}, + * {@link #DIRECTION_INACTIVE}, + * {@link #DIRECTION_RECEIVE}, + * {@link #DIRECTION_SEND}, + * {@link #DIRECTION_SEND_RECEIVE}, + * @param videoQuality The video quality. Can be one of the following: + * {@link #VIDEO_QUALITY_NONE}, + * {@link #VIDEO_QUALITY_QCIF}, + * {@link #VIDEO_QUALITY_QVGA_LANDSCAPE}, + * {@link #VIDEO_QUALITY_QVGA_PORTRAIT}, + * {@link #VIDEO_QUALITY_VGA_LANDSCAPE}, + * {@link #VIDEO_QUALITY_VGA_PORTRAIT}, + * @param videoDirection The video direction. Can be one of the following: + * {@link #DIRECTION_INVALID}, + * {@link #DIRECTION_INACTIVE}, + * {@link #DIRECTION_RECEIVE}, + * {@link #DIRECTION_SEND}, + * {@link #DIRECTION_SEND_RECEIVE}, + * @param rttMode The rtt mode. Can be one of the following: + * {@link #RTT_MODE_DISABLED}, + * {@link #RTT_MODE_FULL} + */ + public ImsStreamMediaProfile(int audioQuality, int audioDirection, + int videoQuality, int videoDirection, int rttMode) { + mAudioQuality = audioQuality; + mAudioDirection = audioDirection; + mVideoQuality = videoQuality; + mVideoDirection = videoDirection; + mRttMode = rttMode; + } + /** @hide */ public ImsStreamMediaProfile() { mAudioQuality = AUDIO_QUALITY_NONE; diff --git a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl index 86f8606ac39f70435e6649c3475717f5aecba651..c7da681b86a3f2710456d11f124db55fa1586b92 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 2fffd36a1a4fe6d720877bc7f630929d56c42fa7..c073d1ab03d6f5f47e9df376336d345f31e7d306 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 98b67c3d37277705ee301fe79a816c909ee1a5ba..2f52c0ac2d9940deaf8e322614b97129a40fd9fb 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 mFeatures; + private final Set 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 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 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 a941a5671f130ebcdbe095f287c1a422104baabd..fbb69ad78bb631269675a0de6a25e337e6457d87 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -823,10 +823,10 @@ interface ITelephony { IImsConfig getImsConfig(int slotId, int feature); /** - * Returns true if emergency calling is available for the MMTEL feature associated with the - * slot specified. - */ - 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. @@ -1358,10 +1358,10 @@ interface ITelephony { /** * Returns carrier name of the given subscription. - *

    Carrier name is a user-facing name of carrier id {@link #getSubscriptionCarrierId(int)}, + *

    Carrier name is a user-facing name of carrier id {@link #getSimCarrierId(int)}, * usually the brand name of the subsidiary (e.g. T-Mobile). Each carrier could configure * multiple {@link #getSimOperatorName() SPN} but should have a single carrier name. - * Carrier name is not canonical identity, use {@link #getSubscriptionCarrierId(int)} instead. + * Carrier name is not canonical identity, use {@link #getSimCarrierId(int)} instead. *

    Returned carrier name is unlocalized. * * @return Carrier name of given subscription id. return {@code null} if subscription is @@ -1438,13 +1438,12 @@ interface ITelephony { * Returns a list of Forbidden PLMNs from the specified SIM App * Returns null if the query fails. * - * - *

    Requires that the calling app has READ_PRIVILEGED_PHONE_STATE + *

    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/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java index da8471fa19eda692441ccd5c0144ef7594f5d696..a182f2be421fc18e4512dc3fcb0d92d7215e45af 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java @@ -26,7 +26,8 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.ITelephony; + +import java.util.function.Supplier; /** Utility class for Telephony permission enforcement. */ public final class TelephonyPermissions { @@ -34,6 +35,9 @@ public final class TelephonyPermissions { private static final boolean DBG = false; + private static final Supplier TELEPHONY_SUPPLIER = () -> + ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); + private TelephonyPermissions() {} /** @@ -41,8 +45,8 @@ public final class TelephonyPermissions { * *

    This method behaves in one of the following ways: *

      - *
    • return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the - * READ_PHONE_STATE runtime permission. + *
    • return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the + * READ_PHONE_STATE runtime permission, or carrier privileges on the given subId. *
    • throw SecurityException: if the caller didn't declare any of these permissions, or, for * apps which support runtime permissions, if the caller does not currently have any of * these permissions. @@ -51,20 +55,30 @@ public final class TelephonyPermissions { * manually (via AppOps). In this case we can't throw as it would break app compatibility, * so we return false to indicate that the calling function should return dummy data. *
    + * + *

    Note: for simplicity, this method always returns false for callers using legacy + * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged. + * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+ + * devices. + * + * @param subId the subId of the relevant subscription; used to check carrier privileges. May be + * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} to skip this check for cases + * where it isn't relevant (hidden APIs, or APIs which are otherwise okay to leave + * inaccesible to carrier-privileged apps). */ public static boolean checkCallingOrSelfReadPhoneState( - Context context, String callingPackage, String message) { - return checkReadPhoneState(context, Binder.getCallingPid(), Binder.getCallingUid(), + Context context, int subId, String callingPackage, String message) { + return checkReadPhoneState(context, subId, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message); } /** * Check whether the app with the given pid/uid can read phone state. * - *

    This method behaves in one of the following ways: + *

    This method behaves in one of the following ways: *

      - *
    • return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the - * READ_PHONE_STATE runtime permission. + *
    • return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the + * READ_PHONE_STATE runtime permission, or carrier privileges on the given subId. *
    • throw SecurityException: if the caller didn't declare any of these permissions, or, for * apps which support runtime permissions, if the caller does not currently have any of * these permissions. @@ -73,9 +87,22 @@ public final class TelephonyPermissions { * manually (via AppOps). In this case we can't throw as it would break app compatibility, * so we return false to indicate that the calling function should return dummy data. *
    + * + *

    Note: for simplicity, this method always returns false for callers using legacy + * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged. + * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+ + * devices. */ public static boolean checkReadPhoneState( - Context context, int pid, int uid, String callingPackage, String message) { + Context context, int subId, int pid, int uid, String callingPackage, String message) { + return checkReadPhoneState( + context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, message); + } + + @VisibleForTesting + public static boolean checkReadPhoneState( + Context context, Supplier telephonySupplier, int subId, int pid, int uid, + String callingPackage, String message) { try { context.enforcePermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message); @@ -83,8 +110,18 @@ public final class TelephonyPermissions { // SKIP checking for run-time permission since caller has PRIVILEGED permission return true; } catch (SecurityException privilegedPhoneStateException) { - context.enforcePermission( - android.Manifest.permission.READ_PHONE_STATE, pid, uid, message); + try { + context.enforcePermission( + android.Manifest.permission.READ_PHONE_STATE, pid, uid, message); + } catch (SecurityException phoneStateException) { + // If we don't have the runtime permission, but do have carrier privileges, that + // suffices for reading phone state. + if (SubscriptionManager.isValidSubscriptionId(subId)) { + enforceCarrierPrivilege(telephonySupplier, subId, uid, message); + return true; + } + throw phoneStateException; + } } // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been @@ -101,14 +138,16 @@ public final class TelephonyPermissions { * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers. */ public static boolean checkCallingOrSelfReadPhoneNumber( - Context context, String callingPackage, String message) { + Context context, int subId, String callingPackage, String message) { return checkReadPhoneNumber( - context, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message); + context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(), + callingPackage, message); } @VisibleForTesting public static boolean checkReadPhoneNumber( - Context context, int pid, int uid, String callingPackage, String message) { + Context context, Supplier telephonySupplier, int subId, int pid, int uid, + String callingPackage, String message) { // Default SMS app can always read it. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); if (appOps.noteOp(AppOpsManager.OP_WRITE_SMS, uid, callingPackage) == @@ -121,7 +160,8 @@ public final class TelephonyPermissions { // First, check if we can read the phone state. try { - return checkReadPhoneState(context, pid, uid, callingPackage, message); + return checkReadPhoneState( + context, telephonySupplier, subId, pid, uid, callingPackage, message); } catch (SecurityException readPhoneStateSecurityException) { } // Can be read with READ_SMS too. @@ -186,16 +226,21 @@ public final class TelephonyPermissions { } private static void enforceCarrierPrivilege(int subId, int uid, String message) { - if (getCarrierPrivilegeStatus(subId, uid) != + enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message); + } + + private static void enforceCarrierPrivilege( + Supplier telephonySupplier, int subId, int uid, String message) { + if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid) != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege."); throw new SecurityException(message); } } - private static int getCarrierPrivilegeStatus(int subId, int uid) { - ITelephony telephony = - ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); + private static int getCarrierPrivilegeStatus( + Supplier telephonySupplier, int subId, int uid) { + ITelephony telephony = telephonySupplier.get(); try { if (telephony != null) { return telephony.getCarrierPrivilegeStatusForUid(subId, uid); diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index b6769d5a2e8a0057fc7f7f0182b012c5680adc6c..ea44d39476238dcd516c3950409a763365b704e1 100755 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -470,6 +470,9 @@ public class SmsMessage extends SmsMessageBase { int bearerDataLength; SmsEnvelope env = new SmsEnvelope(); CdmaSmsAddress addr = new CdmaSmsAddress(); + // We currently do not parse subaddress in PDU, but it is required when determining + // fingerprint (see getIncomingSmsFingerprint()). + CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress(); try { env.messageType = dis.readInt(); @@ -520,6 +523,7 @@ public class SmsMessage extends SmsMessageBase { // link the filled objects to this SMS mOriginatingAddress = addr; env.origAddress = addr; + env.origSubaddress = subaddr; mEnvelope = env; mPdu = pdu; @@ -1015,8 +1019,11 @@ public class SmsMessage extends SmsMessageBase { output.write(mEnvelope.teleService); output.write(mEnvelope.origAddress.origBytes, 0, mEnvelope.origAddress.origBytes.length); output.write(mEnvelope.bearerData, 0, mEnvelope.bearerData.length); - output.write(mEnvelope.origSubaddress.origBytes, 0, - mEnvelope.origSubaddress.origBytes.length); + // subaddress is not set when parsing some MT SMS. + if (mEnvelope.origSubaddress != null && mEnvelope.origSubaddress.origBytes != null) { + output.write(mEnvelope.origSubaddress.origBytes, 0, + mEnvelope.origSubaddress.origBytes.length); + } return output.toByteArray(); } diff --git a/test-mock/api/android-test-mock-current.txt b/test-mock/api/android-test-mock-current.txt index 07acfef7ce6cd53c6f49761dc3df939362b5d800..f3b253c0f46063a19161061953494d7e3b317158 100644 --- a/test-mock/api/android-test-mock-current.txt +++ b/test-mock/api/android-test-mock-current.txt @@ -278,6 +278,7 @@ package android.test.mock { method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int); method public android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int); method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int); + method public android.content.pm.ResolveInfo resolveServiceAsUser(android.content.Intent, int, int); method public void setApplicationCategoryHint(java.lang.String, int); method public void setApplicationEnabledSetting(java.lang.String, int, int); method public void setComponentEnabledSetting(android.content.ComponentName, int, int); diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java index 1af7c3a479b6abe21bb0dfb201b96d86cc0c1a27..8ebb77d7a3504d886e3710db81a655a5a6d928ce 100644 --- a/test-mock/src/android/test/mock/MockPackageManager.java +++ b/test-mock/src/android/test/mock/MockPackageManager.java @@ -18,6 +18,7 @@ package android.test.mock; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.PackageInstallObserver; import android.content.ComponentName; import android.content.Intent; @@ -463,6 +464,11 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + @Override + public ResolveInfo resolveServiceAsUser(Intent intent, int flags, int userId) { + throw new UnsupportedOperationException(); + } + @Override public List queryIntentServices(Intent intent, int flags) { throw new UnsupportedOperationException(); diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index f4b85b209e4f6b66aa8877a5a0e8fc9756cdf57e..dd56e0e41164b751041191bc15285c30a85f28ac 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -76,6 +76,7 @@ public class AppLaunch extends InstrumentationTestCase { private static final String KEY_DROP_CACHE = "drop_cache"; private static final String KEY_SIMPLEPERF_CMD = "simpleperf_cmd"; private static final String KEY_SIMPLEPERF_APP = "simpleperf_app"; + private static final String KEY_CYCLE_CLEAN = "cycle_clean"; private static final String KEY_TRACE_ITERATIONS = "trace_iterations"; private static final String KEY_LAUNCH_DIRECTORY = "launch_directory"; private static final String KEY_TRACE_DIRECTORY = "trace_directory"; @@ -137,6 +138,11 @@ public class AppLaunch extends InstrumentationTestCase { private BufferedWriter mBufferedWriter = null; private boolean mSimplePerfAppOnly = false; private String[] mCompilerFilters = null; + private String mLastAppName = ""; + private boolean mCycleCleanUp = false; + private boolean mIterationCycle = false; + private long mCycleTime = 0; + private StringBuilder mCycleTimes = new StringBuilder(); @Override protected void setUp() throws Exception { @@ -236,6 +242,7 @@ public class AppLaunch extends InstrumentationTestCase { // App launch times for trial launch will not be used for final // launch time calculations. if (launch.getLaunchReason().equals(TRIAL_LAUNCH)) { + mIterationCycle = false; // In the "applaunch.txt" file, trail launches is referenced using // "TRIAL_LAUNCH" String appPkgName = mNameToIntent.get(launch.getApp()) @@ -273,6 +280,7 @@ public class AppLaunch extends InstrumentationTestCase { // App launch times used for final calculation else if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) { + mIterationCycle = true; AppLaunchResult launchResults = null; if (hasFailureOnFirstLaunch(launch)) { // skip if the app has failures while launched first @@ -286,6 +294,7 @@ public class AppLaunch extends InstrumentationTestCase { // if it fails once, skip the rest of the launches continue; } else { + mCycleTime += launchResults.mLaunchTime; addLaunchResult(launch, launchResults); } sleep(POST_LAUNCH_IDLE_TIMEOUT); @@ -294,6 +303,7 @@ public class AppLaunch extends InstrumentationTestCase { // App launch times for trace launch will not be used for final // launch time calculations. else if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) { + mIterationCycle = false; AtraceLogger atraceLogger = AtraceLogger .getAtraceLoggerInstance(getInstrumentation()); // Start the trace @@ -314,6 +324,20 @@ public class AppLaunch extends InstrumentationTestCase { startHomeIntent(); } sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT); + + // If cycle clean up is enabled and last app launched is + // current app then the cycle is completed and eligible for + // cleanup. + if (LAUNCH_ORDER_CYCLIC.equalsIgnoreCase(mLaunchOrder) && mCycleCleanUp + && launch.getApp().equalsIgnoreCase(mLastAppName)) { + // Kill all the apps and drop all the cache + cleanUpAfterCycle(); + if (mIterationCycle) { + // Save the previous cycle time and reset the cycle time to 0 + mCycleTimes.append(String.format("%d,", mCycleTime)); + mCycleTime = 0; + } + } } } finally { if (null != mBufferedWriter) { @@ -321,6 +345,9 @@ public class AppLaunch extends InstrumentationTestCase { } } + if (mCycleTimes.length() != 0) { + mResult.putString("Cycle_Times", mCycleTimes.toString()); + } for (String app : mNameToResultKey.keySet()) { for (String compilerFilter : mCompilerFilters) { StringBuilder launchTimes = new StringBuilder(); @@ -453,6 +480,7 @@ public class AppLaunch extends InstrumentationTestCase { mNameToResultKey.put(parts[0], parts[1]); mNameToLaunchTime.put(parts[0], null); + mLastAppName = parts[0]; } String requiredAccounts = args.getString(KEY_REQUIRED_ACCOUNTS); if (requiredAccounts != null) { @@ -487,6 +515,7 @@ public class AppLaunch extends InstrumentationTestCase { mSimplePerfCmd = args.getString(KEY_SIMPLEPERF_CMD); mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC); mSimplePerfAppOnly = Boolean.parseBoolean(args.getString(KEY_SIMPLEPERF_APP)); + mCycleCleanUp = Boolean.parseBoolean(args.getString(KEY_CYCLE_CLEAN)); mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH)); if (mSimplePerfCmd != null && mSimplePerfAppOnly) { @@ -597,6 +626,18 @@ public class AppLaunch extends InstrumentationTestCase { sleep(POST_LAUNCH_IDLE_TIMEOUT); } + private void cleanUpAfterCycle() { + // Kill all the apps + for (String appName : mNameToIntent.keySet()) { + Log.w(TAG, String.format("killing %s", appName)); + closeApp(appName); + } + // Drop all the cache. + assertNotNull("Issue in dropping the cache", + getInstrumentation().getUiAutomation() + .executeShellCommand(DROP_CACHE_SCRIPT)); + } + private void closeApp(String appName) { Intent startIntent = mNameToIntent.get(appName); if (startIntent != null) { diff --git a/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java index 38c298c5e9ff68a0b14b00d103cb70d372f5125b..d36d84e8f51d280a0aeef68b104d7591882c245e 100644 --- a/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java @@ -229,6 +229,9 @@ public class AppLaunch extends InstrumentationTestCase { setLaunchOrder(); for (LaunchOrder launch : mLaunchOrderList) { + if (mNameToIntent.get(launch.getApp()) == null) { + continue; + } dropCache(); String appPkgName = mNameToIntent.get(launch.getApp()) .getComponent().getPackageName(); diff --git a/tests/OdmApps/Android.mk b/tests/OdmApps/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..64fa65325accb14703bf0b63fb7e81555518c8c6 --- /dev/null +++ b/tests/OdmApps/Android.mk @@ -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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := OdmAppsTest +LOCAL_MODULE_TAGS := tests +LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_JAVA_LIBRARIES := tradefed +LOCAL_COMPATIBILITY_SUITE := device-tests +include $(BUILD_HOST_JAVA_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/OdmApps/AndroidTest.xml b/tests/OdmApps/AndroidTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..2f1283850a97c9572d505c1ec41f0900a8beff43 --- /dev/null +++ b/tests/OdmApps/AndroidTest.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/tests/OdmApps/app/Android.mk b/tests/OdmApps/app/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..9eec0cc4f66fcc34f3a3c79cc4b8bab298c9b20b --- /dev/null +++ b/tests/OdmApps/app/Android.mk @@ -0,0 +1,22 @@ +# 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_PACKAGE_NAME := TestOdmApp +LOCAL_MODULE_TAGS := tests +LOCAL_COMPATIBILITY_SUITE := device-tests +LOCAL_SDK_VERSION := current +include $(BUILD_PACKAGE) diff --git a/core/java/android/security/keystore/recovery/RecoveryControllerException.java b/tests/OdmApps/app/AndroidManifest.xml old mode 100644 new mode 100755 similarity index 57% rename from core/java/android/security/keystore/recovery/RecoveryControllerException.java rename to tests/OdmApps/app/AndroidManifest.xml index 1af61ceac60a1a21da17d29596b34c6ab8bca4a3..84a9ea84b522ea3ae98a24f10b521b227d0089e1 --- a/core/java/android/security/keystore/recovery/RecoveryControllerException.java +++ b/tests/OdmApps/app/AndroidManifest.xml @@ -1,4 +1,5 @@ -/* + + -package android.security.keystore.recovery; + + -import java.security.GeneralSecurityException; - -/** - * @deprecated Not used. - * @hide - */ -public abstract class RecoveryControllerException extends GeneralSecurityException { - RecoveryControllerException() { } - - RecoveryControllerException(String msg) { - super(msg); - } - - public RecoveryControllerException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/tests/OdmApps/priv-app/Android.mk b/tests/OdmApps/priv-app/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..d423133fc9f579c47fbbb65c6c4eb523981f7e7d --- /dev/null +++ b/tests/OdmApps/priv-app/Android.mk @@ -0,0 +1,22 @@ +# 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_PACKAGE_NAME := TestOdmPrivApp +LOCAL_MODULE_TAGS := tests +LOCAL_COMPATIBILITY_SUITE := device-tests +LOCAL_SDK_VERSION := current +include $(BUILD_PACKAGE) diff --git a/media/java/android/media/update/PlaybackState2Provider.java b/tests/OdmApps/priv-app/AndroidManifest.xml old mode 100644 new mode 100755 similarity index 55% rename from media/java/android/media/update/PlaybackState2Provider.java rename to tests/OdmApps/priv-app/AndroidManifest.xml index 66b8fa53974b2773c8f4c02bf927e59133cc37d6..031cf64ea7b178390b6448d29af0999d1187b9fe --- a/media/java/android/media/update/PlaybackState2Provider.java +++ b/tests/OdmApps/priv-app/AndroidManifest.xml @@ -1,5 +1,6 @@ -/* - * Copyright 2018 The Android Open Source Project + + -package android.media.update; + + -import android.os.Bundle; - -/** - * @hide - */ -public interface PlaybackState2Provider { - String toString_impl(); - - int getState_impl(); - - long getPosition_impl(); - - long getBufferedPosition_impl(); - - float getPlaybackSpeed_impl(); - - long getLastPositionUpdateTime_impl(); - - long getCurrentPlaylistItemIndex_impl(); - - Bundle toBundle_impl(); -} diff --git a/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java b/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..de742b80a372c6c6d27a147ae56a744ca6bf961a --- /dev/null +++ b/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java @@ -0,0 +1,35 @@ +/* + * 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 com.android.test.odm.apps; + +import com.android.tradefed.testtype.DeviceTestCase; + +public class OdmAppsTest extends DeviceTestCase { + /** + * Test if /odm/app is working + */ + public void testOdmApp() throws Exception { + assertNotNull(getDevice().getAppPackageInfo("com.android.test.odm.app")); + } + + /** + * Test if /odm/priv-app is working + */ + public void testOdmPrivApp() throws Exception { + assertNotNull(getDevice().getAppPackageInfo("com.android.test.odm.privapp")); + } +} diff --git a/tests/UsageStatsTest/AndroidManifest.xml b/tests/UsageStatsTest/AndroidManifest.xml index c27be7b2d5bf0e2c2e1b5c77da6c5da497e3b9a0..66af45424fba556a809a3cd04cc99b710ea7eac1 100644 --- a/tests/UsageStatsTest/AndroidManifest.xml +++ b/tests/UsageStatsTest/AndroidManifest.xml @@ -21,5 +21,6 @@ + diff --git a/tests/UsageStatsTest/res/menu/main.xml b/tests/UsageStatsTest/res/menu/main.xml index 4ccbc81ab3171db05cf6c4bed05f6dc09c5131c7..612267c85b1b9ae895a4f99fef8bb966d524dca8 100644 --- a/tests/UsageStatsTest/res/menu/main.xml +++ b/tests/UsageStatsTest/res/menu/main.xml @@ -4,4 +4,6 @@ android:title="View Log"/> + diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java index 9429d9bbf89b066edf06e818e949b62f12a4e185..3d8ce21a2c007673a9d1f4ae2e435b36f5899f01 100644 --- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java +++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java @@ -18,6 +18,7 @@ package com.android.tests.usagestats; import android.app.AlertDialog; import android.app.ListActivity; +import android.app.PendingIntent; import android.app.usage.UsageStats; import android.app.usage.UsageStatsManager; import android.content.Context; @@ -36,14 +37,17 @@ import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.EditText; import android.widget.TextView; +import android.widget.Toast; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Map; +import java.util.concurrent.TimeUnit; public class UsageStatsActivity extends ListActivity { private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14; + private static final String EXTRA_KEY_TIMEOUT = "com.android.tests.usagestats.extra.TIMEOUT"; private UsageStatsManager mUsageStatsManager; private Adapter mAdapter; private Comparator mComparator = new Comparator() { @@ -59,6 +63,20 @@ public class UsageStatsActivity extends ListActivity { mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); mAdapter = new Adapter(); setListAdapter(mAdapter); + Bundle extras = getIntent().getExtras(); + if (extras != null && extras.containsKey(UsageStatsManager.EXTRA_TIME_USED)) { + System.err.println("UsageStatsActivity " + extras); + Toast.makeText(this, "Timeout of observed app\n" + extras, Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onNewIntent(Intent intent) { + Bundle extras = intent.getExtras(); + if (extras != null && extras.containsKey(UsageStatsManager.EXTRA_TIME_USED)) { + System.err.println("UsageStatsActivity " + extras); + Toast.makeText(this, "Timeout of observed app\n" + extras, Toast.LENGTH_SHORT).show(); + } } @Override @@ -77,7 +95,9 @@ public class UsageStatsActivity extends ListActivity { case R.id.call_is_app_inactive: callIsAppInactive(); return true; - + case R.id.set_app_limit: + callSetAppLimit(); + return true; default: return super.onOptionsItemSelected(item); } @@ -116,6 +136,40 @@ public class UsageStatsActivity extends ListActivity { builder.show(); } + private void callSetAppLimit() { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("Enter package name"); + final EditText input = new EditText(this); + input.setInputType(InputType.TYPE_CLASS_TEXT); + input.setHint("com.android.tests.usagestats"); + builder.setView(input); + + builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + final String packageName = input.getText().toString().trim(); + if (!TextUtils.isEmpty(packageName)) { + String[] packages = packageName.split(","); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClass(UsageStatsActivity.this, UsageStatsActivity.class); + intent.setPackage(getPackageName()); + intent.putExtra(EXTRA_KEY_TIMEOUT, true); + mUsageStatsManager.registerAppUsageObserver(1, packages, + 30, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this, + 1, intent, 0)); + } + } + }); + builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.show(); + } + private void showInactive(String packageName) { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage( diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp index ac28227b8778326b78b652f16778b5248c07214c..4a4260d1d3231aad71cd4c5b7f434a7209cf83e2 100644 --- a/tools/aapt2/LoadedApk.cpp +++ b/tools/aapt2/LoadedApk.cpp @@ -22,6 +22,7 @@ #include "format/binary/TableFlattener.h" #include "format/binary/XmlFlattener.h" #include "format/proto/ProtoDeserialize.h" +#include "format/proto/ProtoSerialize.h" #include "io/BigBufferStream.h" #include "io/Util.h" #include "xml/XmlDom.h" @@ -110,7 +111,7 @@ std::unique_ptr LoadedApk::LoadProtoApkFromFileCollection( return {}; } return util::make_unique(source, std::move(collection), std::move(table), - std::move(manifest)); + std::move(manifest), ApkFormat::kProto); } std::unique_ptr LoadedApk::LoadBinaryApkFromFileCollection( @@ -153,7 +154,7 @@ std::unique_ptr LoadedApk::LoadBinaryApkFromFileCollection( return {}; } return util::make_unique(source, std::move(collection), std::move(table), - std::move(manifest)); + std::move(manifest), ApkFormat::kBinary); } bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOptions& options, @@ -205,7 +206,7 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table } // The resource table needs to be re-serialized since it might have changed. - if (path == "resources.arsc") { + if (format_ == ApkFormat::kBinary && path == kApkResourceTablePath) { BigBuffer buffer(4096); // TODO(adamlesinski): How to determine if there were sparse entries (and if to encode // with sparse entries) b/35389232. @@ -215,11 +216,22 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table } io::BigBufferInputStream input_stream(&buffer); - if (!io::CopyInputStreamToArchive(context, &input_stream, path, ArchiveEntry::kAlign, + if (!io::CopyInputStreamToArchive(context, + &input_stream, + path, + ArchiveEntry::kAlign, writer)) { return false; } - + } else if (format_ == ApkFormat::kProto && path == kProtoResourceTablePath) { + pb::ResourceTable pb_table; + SerializeTableToPb(*split_table, &pb_table); + if (!io::CopyProtoToArchive(context, + &pb_table, + path, + ArchiveEntry::kAlign, writer)) { + return false; + } } else if (manifest != nullptr && path == "AndroidManifest.xml") { BigBuffer buffer(8192); XmlFlattenerOptions xml_flattener_options; @@ -246,9 +258,9 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table } ApkFormat LoadedApk::DetermineApkFormat(io::IFileCollection* apk) { - if (apk->FindFile("resources.arsc") != nullptr) { + if (apk->FindFile(kApkResourceTablePath) != nullptr) { return ApkFormat::kBinary; - } else if (apk->FindFile("resources.pb") != nullptr) { + } else if (apk->FindFile(kProtoResourceTablePath) != nullptr) { return ApkFormat::kProto; } else { // If the resource table is not present, attempt to read the manifest. diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h index 81bcecc3ca5d64660f6cb7d56fbe134b79c3d8b7..41f879d0cdc3d3560811bbd51da6cd88ffd62cdd 100644 --- a/tools/aapt2/LoadedApk.h +++ b/tools/aapt2/LoadedApk.h @@ -57,11 +57,13 @@ class LoadedApk { const Source& source, std::unique_ptr collection, IDiagnostics* diag); LoadedApk(const Source& source, std::unique_ptr apk, - std::unique_ptr table, std::unique_ptr manifest) + std::unique_ptr table, std::unique_ptr manifest, + const ApkFormat& format) : source_(source), apk_(std::move(apk)), table_(std::move(table)), - manifest_(std::move(manifest)) { + manifest_(std::move(manifest)), + format_(format) { } io::IFileCollection* GetFileCollection() { @@ -112,6 +114,7 @@ class LoadedApk { std::unique_ptr apk_; std::unique_ptr table_; std::unique_ptr manifest_; + ApkFormat format_; static ApkFormat DetermineApkFormat(io::IFileCollection* apk); }; diff --git a/tools/aapt2/optimize/MultiApkGenerator_test.cpp b/tools/aapt2/optimize/MultiApkGenerator_test.cpp index e1d951fc9776455476976c9738ec6a67bc615b7c..80eb737fa682a0a1b82a8c69fbefaa6def0c9004 100644 --- a/tools/aapt2/optimize/MultiApkGenerator_test.cpp +++ b/tools/aapt2/optimize/MultiApkGenerator_test.cpp @@ -104,7 +104,7 @@ class MultiApkGeneratorTest : public ::testing::Test { TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) { std::unique_ptr table = BuildTable(); - LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}}; + LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}, kBinary}; std::unique_ptr ctx = test::ContextBuilder().SetMinSdkVersion(19).Build(); FilterChain chain; @@ -131,7 +131,7 @@ TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) { TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) { std::unique_ptr table = BuildTable(); - LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}}; + LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}, kBinary}; std::unique_ptr ctx = test::ContextBuilder().SetMinSdkVersion(1).Build(); FilterChain chain; @@ -156,7 +156,7 @@ TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) { TEST_F(MultiApkGeneratorTest, VersionFilterNoVersion) { std::unique_ptr table = BuildTable(); - LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}}; + LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}, kBinary}; std::unique_ptr ctx = test::ContextBuilder().SetMinSdkVersion(1).Build(); FilterChain chain; diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp index 8219150d30291478a8ed00fad00c64986c597488..7e922e6528de37c4adb32bf277f7cc127f34f2d6 100644 --- a/tools/incident_section_gen/main.cpp +++ b/tools/incident_section_gen/main.cpp @@ -427,6 +427,7 @@ static bool generateSectionListCpp(Descriptor const* descriptor) { printf(" new GZipSection(%d,", field->number()); splitAndPrint(s.args()); printf(" NULL),\n"); + break; case SECTION_TOMBSTONE: printf(" new TombstoneSection(%d, \"%s\"),\n", field->number(), s.args().c_str()); break; diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp index ab106d708748edf0882965d502e731ec548f73a3..ebdcdfdd6c500fb617dc76398eaca16ca9007ec0 100644 --- a/tools/stats_log_api_gen/Collation.cpp +++ b/tools/stats_log_api_gen/Collation.cpp @@ -46,7 +46,8 @@ AtomDecl::AtomDecl(const AtomDecl& that) message(that.message), fields(that.fields), primaryFields(that.primaryFields), - exclusiveField(that.exclusiveField) {} + exclusiveField(that.exclusiveField), + uidField(that.uidField) {} AtomDecl::AtomDecl(int c, const string& n, const string& m) :code(c), @@ -262,6 +263,18 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, errorCount++; } } + + if (field->options().GetExtension(os::statsd::is_uid) == true) { + if (javaType != JAVA_TYPE_INT) { + errorCount++; + } + + if (atomDecl->uidField == 0) { + atomDecl->uidField = it->first; + } else { + errorCount++; + } + } } return errorCount; diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h index edba3e2222249416f81588b7c078cd882af4f0e5..5d2c30292c9c6b4027ace94de272ce9c33706fb3 100644 --- a/tools/stats_log_api_gen/Collation.h +++ b/tools/stats_log_api_gen/Collation.h @@ -84,6 +84,8 @@ struct AtomDecl { vector primaryFields; int exclusiveField = 0; + int uidField = 0; + AtomDecl(); AtomDecl(const AtomDecl& that); AtomDecl(int code, const string& name, const string& message); diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index d58c2232972cfeada4aa942a3b57adcd3df43eeb..300c701bfc80bd017f8e7af44626c3cb1c0f0337 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -113,6 +113,98 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, "// the single event tag id for all stats logs\n"); fprintf(out, "const static int kStatsEventTag = 1937006964;\n"); + std::set kTruncatingAtomNames = {"mobile_radio_power_state_changed", + "audio_state_changed", + "call_state_changed", + "phone_signal_strength_changed", + "mobile_bytes_transfer_by_fg_bg", + "mobile_bytes_transfer"}; + fprintf(out, + "const std::set " + "AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n"); + for (set::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (kTruncatingAtomNames.find(atom->name) == + kTruncatingAtomNames.end()) { + string constant = make_constant_name(atom->name); + fprintf(out, " %s,\n", constant.c_str()); + } + } + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, + "const std::set AtomsInfo::kAtomsWithAttributionChain = {\n"); + for (set::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + for (vector::const_iterator field = atom->fields.begin(); + field != atom->fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { + string constant = make_constant_name(atom->name); + fprintf(out, " %s,\n", constant.c_str()); + break; + } + } + } + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, + "static std::map " + "getAtomUidField() {\n"); + fprintf(out, " std::map uidField;\n"); + for (set::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->uidField == 0) { + continue; + } + fprintf(out, + "\n // Adding uid field for atom " + "(%d)%s\n", + atom->code, atom->name.c_str()); + fprintf(out, " uidField[static_cast(%s)] = %d;\n", + make_constant_name(atom->name).c_str(), atom->uidField); + } + + fprintf(out, " return uidField;\n"); + fprintf(out, "};\n"); + + fprintf(out, + "const std::map AtomsInfo::kAtomsWithUidField = " + "getAtomUidField();\n"); + + fprintf(out, + "static std::map " + "getStateAtomFieldOptions() {\n"); + fprintf(out, " std::map options;\n"); + fprintf(out, " StateAtomFieldOptions opt;\n"); + for (set::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) { + continue; + } + fprintf(out, + "\n // Adding primary and exclusive fields for atom " + "(%d)%s\n", + atom->code, atom->name.c_str()); + fprintf(out, " opt.primaryFields.clear();\n"); + for (const auto& field : atom->primaryFields) { + fprintf(out, " opt.primaryFields.push_back(%d);\n", field); + } + + fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField); + fprintf(out, " options[static_cast(%s)] = opt;\n", + make_constant_name(atom->name).c_str()); + } + + fprintf(out, " return options;\n"); + fprintf(out, " }\n"); + + fprintf(out, + "const std::map " + "AtomsInfo::kStateAtomsFieldOptions = " + "getStateAtomFieldOptions();\n"); + // Print write methods fprintf(out, "\n"); for (set>::const_iterator signature = atoms.signatures.begin(); @@ -366,89 +458,26 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio fprintf(out, "};\n"); fprintf(out, "\n"); - std::set kTruncatingAtomNames = - { "mobile_radio_power_state_changed", "audio_state_changed", "call_state_changed", - "phone_signal_strength_changed", "mobile_bytes_transfer_by_fg_bg", - "mobile_bytes_transfer"}; - fprintf(out, "const static std::set kNotTruncatingTimestampAtomWhiteList = {\n"); - for (set::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - if (kTruncatingAtomNames.find(atom->name) == kTruncatingAtomNames.end()) { - string constant = make_constant_name(atom->name); - fprintf(out, " %s,\n", constant.c_str()); - } - } - fprintf(out, "};\n"); - fprintf(out, "\n"); - - fprintf(out, "const static std::set kAtomsWithUidField = {\n"); - for (set::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - for (vector::const_iterator field = atom->fields.begin(); - field != atom->fields.end(); field++) { - if (field->name == "uid") { - string constant = make_constant_name(atom->name); - fprintf(out, " %s,\n", constant.c_str()); - break; - } - } - } - fprintf(out, "};\n"); - fprintf(out, "\n"); - - fprintf(out, "const static std::set kAtomsWithAttributionChain = {\n"); - for (set::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - for (vector::const_iterator field = atom->fields.begin(); - field != atom->fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - string constant = make_constant_name(atom->name); - fprintf(out, " %s,\n", constant.c_str()); - break; - } - } - } - fprintf(out, "};\n"); - fprintf(out, "\n"); - - fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", maxPushedAtomId); - fprintf(out, "struct StateAtomFieldOptions {\n"); fprintf(out, " std::vector primaryFields;\n"); fprintf(out, " int exclusiveField;\n"); + fprintf(out, "};\n"); fprintf(out, "\n"); - fprintf(out, - " static std::map " - "getStateAtomFieldOptions() {\n"); - fprintf(out, " std::map options;\n"); - fprintf(out, " StateAtomFieldOptions opt;\n"); - for (set::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) { - continue; - } - fprintf(out, - "\n // Adding primary and exclusive fields for atom " - "(%d)%s\n", - atom->code, atom->name.c_str()); - fprintf(out, " opt.primaryFields.clear();\n"); - for (const auto& field : atom->primaryFields) { - fprintf(out, " opt.primaryFields.push_back(%d);\n", field); - } - - fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField); - fprintf(out, " options[static_cast(%s)] = opt;\n", - make_constant_name(atom->name).c_str()); - } - fprintf(out, " return options;\n"); - fprintf(out, " }\n"); + fprintf(out, "struct AtomsInfo {\n"); + fprintf(out, + " const static std::set " + "kNotTruncatingTimestampAtomWhiteList;\n"); + fprintf(out, " const static std::map kAtomsWithUidField;\n"); + fprintf(out, + " const static std::set kAtomsWithAttributionChain;\n"); + fprintf(out, + " const static std::map " + "kStateAtomsFieldOptions;\n"); fprintf(out, "};\n"); - fprintf(out, - "const static std::map " - "kStateAtomsFieldOptions = " - "StateAtomFieldOptions::getStateAtomFieldOptions();\n"); + fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", + maxPushedAtomId); // Print write methods fprintf(out, "//\n"); diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 309bc80b8864336c2d9883fc034c6d23e40bd18d..2f7b50d1bd0c060865ecc09d8dd37a5513fa4ed0 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -28,7 +28,6 @@ import android.net.Network; import android.net.wifi.ISoftApCallback; import android.net.wifi.PasspointManagementObjectDefinition; import android.net.wifi.ScanResult; -import android.net.wifi.ScanSettings; import android.net.wifi.WifiActivityEnergyInfo; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; @@ -86,7 +85,7 @@ interface IWifiManager boolean disableNetwork(int netId, String packageName); - void startScan(in ScanSettings requested, in WorkSource ws, String packageName); + void startScan(String packageName); List getScanResults(String callingPackage); diff --git a/wifi/java/android/net/wifi/ScanSettings.java b/wifi/java/android/net/wifi/ScanSettings.java deleted file mode 100644 index 094ce34afb81ebcbb86269124f765fef2d71a257..0000000000000000000000000000000000000000 --- a/wifi/java/android/net/wifi/ScanSettings.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.net.wifi; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.ArrayList; -import java.util.Collection; - -/** - * Bundle of customized scan settings - * - * @see WifiManager#startCustomizedScan - * - * @hide - */ -public class ScanSettings implements Parcelable { - - /** channel set to scan. this can be null or empty, indicating a full scan */ - public Collection channelSet; - - /** public constructor */ - public ScanSettings() { } - - /** copy constructor */ - public ScanSettings(ScanSettings source) { - if (source.channelSet != null) - channelSet = new ArrayList(source.channelSet); - } - - /** check for validity */ - public boolean isValid() { - for (WifiChannel channel : channelSet) - if (!channel.isValid()) return false; - return true; - } - - /** implement Parcelable interface */ - @Override - public int describeContents() { - return 0; - } - - /** implement Parcelable interface */ - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(channelSet == null ? 0 : channelSet.size()); - if (channelSet != null) - for (WifiChannel channel : channelSet) channel.writeToParcel(out, flags); - } - - /** implement Parcelable interface */ - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public ScanSettings createFromParcel(Parcel in) { - ScanSettings settings = new ScanSettings(); - int size = in.readInt(); - if (size > 0) { - settings.channelSet = new ArrayList(size); - while (size-- > 0) - settings.channelSet.add(WifiChannel.CREATOR.createFromParcel(in)); - } - return settings; - } - - @Override - public ScanSettings[] newArray(int size) { - return new ScanSettings[size]; - } - }; -} diff --git a/wifi/java/android/net/wifi/WifiChannel.java b/wifi/java/android/net/wifi/WifiChannel.java deleted file mode 100644 index 640481ee62613d905031355dea69940f20cc0e98..0000000000000000000000000000000000000000 --- a/wifi/java/android/net/wifi/WifiChannel.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.net.wifi; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Wifi Channel - * - * @see ScanSettings - * - * @hide - */ -public class WifiChannel implements Parcelable { - - private static final int MIN_FREQ_MHZ = 2412; - private static final int MAX_FREQ_MHZ = 5825; - - private static final int MIN_CHANNEL_NUM = 1; - private static final int MAX_CHANNEL_NUM = 196; - - /** frequency */ - public int freqMHz; - - /** channel number */ - public int channelNum; - - /** is it a DFS channel? */ - public boolean isDFS; - - /** public constructor */ - public WifiChannel() { } - - /** check for validity */ - public boolean isValid() { - if (freqMHz < MIN_FREQ_MHZ || freqMHz > MAX_FREQ_MHZ) return false; - if (channelNum < MIN_CHANNEL_NUM || channelNum > MAX_CHANNEL_NUM) return false; - return true; - } - - /** implement Parcelable interface */ - @Override - public int describeContents() { - return 0; - } - - /** implement Parcelable interface */ - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(freqMHz); - out.writeInt(channelNum); - out.writeInt(isDFS ? 1 : 0); - } - - /** implement Parcelable interface */ - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public WifiChannel createFromParcel(Parcel in) { - WifiChannel channel = new WifiChannel(); - channel.freqMHz = in.readInt(); - channel.channelNum = in.readInt(); - channel.isDFS = in.readInt() != 0; - return channel; - } - - @Override - public WifiChannel[] newArray(int size) { - return new WifiChannel[size]; - } - }; -} diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 93fa5987aa9c08bd0a7ad8fb5d36d4191af2d5c8..21ae3a9239469fac80da49f4d6b0a1b93f720fac 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" }; } @@ -532,91 +529,6 @@ public class WifiConfiguration implements Parcelable { /** @hide **/ public static int INVALID_RSSI = -127; - /** - * @hide - * A summary of the RSSI and Band status for that configuration - * This is used as a temporary value by the auto-join controller - */ - public static final class Visibility { - public int rssi5; // strongest 5GHz RSSI - public int rssi24; // strongest 2.4GHz RSSI - public int num5; // number of BSSIDs on 5GHz - public int num24; // number of BSSIDs on 2.4GHz - public long age5; // timestamp of the strongest 5GHz BSSID (last time it was seen) - public long age24; // timestamp of the strongest 2.4GHz BSSID (last time it was seen) - public String BSSID24; - public String BSSID5; - public int score; // Debug only, indicate last score used for autojoin/cell-handover - public int currentNetworkBoost; // Debug only, indicate boost applied to RSSI if current - public int bandPreferenceBoost; // Debug only, indicate boost applied to RSSI if current - public int lastChoiceBoost; // Debug only, indicate last choice applied to this configuration - public String lastChoiceConfig; // Debug only, indicate last choice applied to this configuration - - public Visibility() { - rssi5 = INVALID_RSSI; - rssi24 = INVALID_RSSI; - } - - public Visibility(Visibility source) { - rssi5 = source.rssi5; - rssi24 = source.rssi24; - age24 = source.age24; - age5 = source.age5; - num24 = source.num24; - num5 = source.num5; - BSSID5 = source.BSSID5; - BSSID24 = source.BSSID24; - } - - @Override - public String toString() { - StringBuilder sbuf = new StringBuilder(); - sbuf.append("["); - if (rssi24 > INVALID_RSSI) { - sbuf.append(Integer.toString(rssi24)); - sbuf.append(","); - sbuf.append(Integer.toString(num24)); - if (BSSID24 != null) sbuf.append(",").append(BSSID24); - } - sbuf.append("; "); - if (rssi5 > INVALID_RSSI) { - sbuf.append(Integer.toString(rssi5)); - sbuf.append(","); - sbuf.append(Integer.toString(num5)); - if (BSSID5 != null) sbuf.append(",").append(BSSID5); - } - if (score != 0) { - sbuf.append("; ").append(score); - sbuf.append(", ").append(currentNetworkBoost); - sbuf.append(", ").append(bandPreferenceBoost); - if (lastChoiceConfig != null) { - sbuf.append(", ").append(lastChoiceBoost); - sbuf.append(", ").append(lastChoiceConfig); - } - } - sbuf.append("]"); - return sbuf.toString(); - } - } - - /** @hide - * Cache the visibility status of this configuration. - * Visibility can change at any time depending on scan results availability. - * Owner of the WifiConfiguration is responsible to set this field based on - * recent scan results. - ***/ - public Visibility visibility; - - /** @hide - * calculate and set Visibility for that configuration. - * - * age in milliseconds: we will consider only ScanResults that are more recent, - * i.e. younger. - ***/ - public void setVisibility(Visibility status) { - visibility = status; - } - // States for the userApproved field /** * @hide @@ -2181,9 +2093,6 @@ public class WifiConfiguration implements Parcelable { meteredHint = source.meteredHint; meteredOverride = source.meteredOverride; useExternalScores = source.useExternalScores; - if (source.visibility != null) { - visibility = new Visibility(source.visibility); - } didSelfAdd = source.didSelfAdd; lastConnectUid = source.lastConnectUid; diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 8ccccf4c7e5aa96fbc4cffc968bb2c26d111e402..dc3b7a9a5b221173c6784441c03798574c5ee723 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1653,7 +1653,7 @@ public class WifiManager { public boolean startScan(WorkSource workSource) { try { String packageName = mContext.getOpPackageName(); - mService.startScan(null, workSource, packageName); + mService.startScan(packageName); return true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java index eca840644fc6cbc229c5dbb0d2106010c56fb855..ebf60076bd0295541db254604e9f2189024165ba 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 matchFilter, int distanceMm) { diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java index 2ec3b704f0f93eb52c35e1f606d426b0f2aa4f51..51353c618b979089e8e1628232d3aa55dbccd34a 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) and 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. *

    * 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) and 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. *

    * 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 936a1f2b6a47049ebfbfa792bb23d503ef855cac..7fe85be809640d5522edf4130694b11d027dc6c3 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()}. *

    + * Note: the measured distance may be negative for very close devices. + *

    * 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. *

    * 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. *

    * Note: the information is NOT validated - use with caution. Consider validating it with * other sources of information before using it.