diff options
197 files changed, 7293 insertions, 2196 deletions
diff --git a/Android.bp b/Android.bp index 985d73476142..010f496cfb90 100644 --- a/Android.bp +++ b/Android.bp @@ -133,6 +133,8 @@ java_library { "core/java/android/content/pm/IPackageStatsObserver.aidl", "core/java/android/content/pm/IPinItemRequest.aidl", "core/java/android/content/pm/IShortcutService.aidl", + "core/java/android/content/pm/dex/IArtManager.aidl", + "core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl", "core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl", "core/java/android/database/IContentObserver.aidl", ":libcamera_client_aidl", diff --git a/Android.mk b/Android.mk index ea75b19c7ff8..95c3340cd530 100644 --- a/Android.mk +++ b/Android.mk @@ -36,7 +36,7 @@ aidl_parcelables := define stubs-to-aidl-parcelables gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/$1.aidl aidl_parcelables += $$(gen) - $$(gen): $(call java-lib-header-files,$1) | $(HOST_OUT_EXECUTABLES)/sdkparcelables + $$(gen): $(call java-lib-header-files,$1) $(HOST_OUT_EXECUTABLES)/sdkparcelables @echo Extract SDK parcelables: $$@ rm -f $$@ $(HOST_OUT_EXECUTABLES)/sdkparcelables $$< $$@ @@ -694,6 +694,8 @@ LOCAL_SOURCE_FILES_ALL_GENERATED := true LOCAL_SRC_FILES := \ $(call all-proto-files-under, core/proto) \ $(call all-proto-files-under, libs/incident/proto) +# b/72714520 +LOCAL_ERROR_PRONE_FLAGS := -Xep:MissingOverride:OFF include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/api/current.txt b/api/current.txt index e047bdc0ef61..45f38ae9b0d0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5987,16 +5987,16 @@ package android.app { method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow(); - method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo(); + method public android.accessibilityservice.AccessibilityServiceInfo getServiceInfo(); method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats(); method public android.view.WindowContentFrameStats getWindowContentFrameStats(int); method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows(); method public boolean injectInputEvent(android.view.InputEvent, boolean); - method public final boolean performGlobalAction(int); + method public boolean performGlobalAction(int); method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener); method public boolean setRotation(int); method public void setRunAsMonkey(boolean); - method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo); + method public void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo); method public android.graphics.Bitmap takeScreenshot(); method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException; field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1 @@ -6534,6 +6534,7 @@ package android.app.admin { field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2 field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1 field public static final int SKIP_SETUP_WIZARD = 1; // 0x1 + field public static final int WIPE_EUICC = 4; // 0x4 field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1 field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2 } @@ -9048,6 +9049,7 @@ package android.content { field public static final java.lang.String DISPLAY_SERVICE = "display"; field public static final java.lang.String DOWNLOAD_SERVICE = "download"; field public static final java.lang.String DROPBOX_SERVICE = "dropbox"; + field public static final java.lang.String EUICC_SERVICE = "euicc"; field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint"; field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties"; field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method"; @@ -10851,6 +10853,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_SIP_VOIP = "android.software.sip.voip"; field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony"; field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma"; + field public static final java.lang.String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc"; field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm"; field public static final java.lang.String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms"; field public static final deprecated java.lang.String FEATURE_TELEVISION = "android.hardware.type.television"; @@ -11189,15 +11192,15 @@ package android.content.res { public final class AssetManager implements java.lang.AutoCloseable { method public void close(); - method public final java.lang.String[] getLocales(); - method public final java.lang.String[] list(java.lang.String) throws java.io.IOException; - method public final java.io.InputStream open(java.lang.String) throws java.io.IOException; - method public final java.io.InputStream open(java.lang.String, int) throws java.io.IOException; - method public final android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException; - method public final android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException; - method public final android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException; - method public final android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException; - method public final android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException; + method public java.lang.String[] getLocales(); + method public java.lang.String[] list(java.lang.String) throws java.io.IOException; + method public java.io.InputStream open(java.lang.String) throws java.io.IOException; + method public java.io.InputStream open(java.lang.String, int) throws java.io.IOException; + method public android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException; + method public android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException; + method public android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException; + method public android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException; + method public android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException; field public static final int ACCESS_BUFFER = 3; // 0x3 field public static final int ACCESS_RANDOM = 1; // 0x1 field public static final int ACCESS_STREAMING = 2; // 0x2 @@ -11205,15 +11208,9 @@ package android.content.res { } public final class AssetManager.AssetInputStream extends java.io.InputStream { - method public final int available() throws java.io.IOException; - method public final void close() throws java.io.IOException; - method public final void mark(int); - method public final boolean markSupported(); - method public final int read() throws java.io.IOException; - method public final int read(byte[]) throws java.io.IOException; - method public final int read(byte[], int, int) throws java.io.IOException; - method public final void reset() throws java.io.IOException; - method public final long skip(long) throws java.io.IOException; + method public void mark(int); + method public int read() throws java.io.IOException; + method public void reset() throws java.io.IOException; } public class ColorStateList implements android.os.Parcelable { @@ -11973,7 +11970,7 @@ package android.database.sqlite { method public java.util.List<android.util.Pair<java.lang.String, java.lang.String>> getAttachedDbs(); method public long getMaximumSize(); method public long getPageSize(); - method public final java.lang.String getPath(); + method public java.lang.String getPath(); method public deprecated java.util.Map<java.lang.String, java.lang.String> getSyncedTables(); method public int getVersion(); method public boolean inTransaction(); @@ -12625,29 +12622,29 @@ package android.graphics { method public void eraseColor(int); method public android.graphics.Bitmap extractAlpha(); method public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]); - method public final int getAllocationByteCount(); - method public final int getByteCount(); - method public final android.graphics.ColorSpace getColorSpace(); - method public final android.graphics.Bitmap.Config getConfig(); + method public int getAllocationByteCount(); + method public int getByteCount(); + method public android.graphics.ColorSpace getColorSpace(); + method public android.graphics.Bitmap.Config getConfig(); method public int getDensity(); method public int getGenerationId(); - method public final int getHeight(); + method public int getHeight(); method public byte[] getNinePatchChunk(); method public int getPixel(int, int); method public void getPixels(int[], int, int, int, int, int, int); - method public final int getRowBytes(); + method public int getRowBytes(); method public int getScaledHeight(android.graphics.Canvas); method public int getScaledHeight(android.util.DisplayMetrics); method public int getScaledHeight(int); method public int getScaledWidth(android.graphics.Canvas); method public int getScaledWidth(android.util.DisplayMetrics); method public int getScaledWidth(int); - method public final int getWidth(); - method public final boolean hasAlpha(); - method public final boolean hasMipMap(); - method public final boolean isMutable(); - method public final boolean isPremultiplied(); - method public final boolean isRecycled(); + method public int getWidth(); + method public boolean hasAlpha(); + method public boolean hasMipMap(); + method public boolean isMutable(); + method public boolean isPremultiplied(); + method public boolean isRecycled(); method public void prepareToDraw(); method public void reconfigure(int, int, android.graphics.Bitmap.Config); method public void recycle(); @@ -12655,11 +12652,11 @@ package android.graphics { method public void setConfig(android.graphics.Bitmap.Config); method public void setDensity(int); method public void setHasAlpha(boolean); - method public final void setHasMipMap(boolean); + method public void setHasMipMap(boolean); method public void setHeight(int); method public void setPixel(int, int, int); method public void setPixels(int[], int, int, int, int, int, int); - method public final void setPremultiplied(boolean); + method public void setPremultiplied(boolean); method public void setWidth(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.graphics.Bitmap> CREATOR; @@ -12731,7 +12728,7 @@ package android.graphics { method public android.graphics.Bitmap decodeRegion(android.graphics.Rect, android.graphics.BitmapFactory.Options); method public int getHeight(); method public int getWidth(); - method public final boolean isRecycled(); + method public boolean isRecycled(); method public static android.graphics.BitmapRegionDecoder newInstance(byte[], int, int, boolean) throws java.io.IOException; method public static android.graphics.BitmapRegionDecoder newInstance(java.io.FileDescriptor, boolean) throws java.io.IOException; method public static android.graphics.BitmapRegionDecoder newInstance(java.io.InputStream, boolean) throws java.io.IOException; @@ -13734,22 +13731,22 @@ package android.graphics { ctor public Rect(); ctor public Rect(int, int, int, int); ctor public Rect(android.graphics.Rect); - method public final int centerX(); - method public final int centerY(); + method public int centerX(); + method public int centerY(); method public boolean contains(int, int); method public boolean contains(int, int, int, int); method public boolean contains(android.graphics.Rect); method public int describeContents(); - method public final float exactCenterX(); - method public final float exactCenterY(); + method public float exactCenterX(); + method public float exactCenterY(); method public java.lang.String flattenToString(); - method public final int height(); + method public int height(); method public void inset(int, int); method public boolean intersect(int, int, int, int); method public boolean intersect(android.graphics.Rect); method public boolean intersects(int, int, int, int); method public static boolean intersects(android.graphics.Rect, android.graphics.Rect); - method public final boolean isEmpty(); + method public boolean isEmpty(); method public void offset(int, int); method public void offsetTo(int, int); method public void readFromParcel(android.os.Parcel); @@ -13763,7 +13760,7 @@ package android.graphics { method public void union(int, int, int, int); method public void union(android.graphics.Rect); method public void union(int, int); - method public final int width(); + method public int width(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.graphics.Rect> CREATOR; field public int bottom; @@ -15299,9 +15296,7 @@ package android.hardware.camera2 { } public static final class CameraCharacteristics.Key<T> { - method public final boolean equals(java.lang.Object); method public java.lang.String getName(); - method public final int hashCode(); } public abstract class CameraConstrainedHighSpeedCaptureSession extends android.hardware.camera2.CameraCaptureSession { @@ -15643,9 +15638,7 @@ package android.hardware.camera2 { } public static final class CaptureRequest.Key<T> { - method public final boolean equals(java.lang.Object); method public java.lang.String getName(); - method public final int hashCode(); } public class CaptureResult extends android.hardware.camera2.CameraMetadata { @@ -15733,9 +15726,7 @@ package android.hardware.camera2 { } public static final class CaptureResult.Key<T> { - method public final boolean equals(java.lang.Object); method public java.lang.String getName(); - method public final int hashCode(); } public final class DngCreator implements java.lang.AutoCloseable { @@ -15843,7 +15834,7 @@ package android.hardware.camera2.params { method public float getComponent(int); method public float getGreenEven(); method public float getGreenOdd(); - method public final float getRed(); + method public float getRed(); field public static final int BLUE = 3; // 0x3 field public static final int COUNT = 4; // 0x4 field public static final int GREEN_EVEN = 1; // 0x1 @@ -15857,16 +15848,16 @@ package android.hardware.camera2.params { method public android.util.Range<java.lang.Integer>[] getHighSpeedVideoFpsRangesFor(android.util.Size); method public android.util.Size[] getHighSpeedVideoSizes(); method public android.util.Size[] getHighSpeedVideoSizesFor(android.util.Range<java.lang.Integer>); - method public final int[] getInputFormats(); + method public int[] getInputFormats(); method public android.util.Size[] getInputSizes(int); - method public final int[] getOutputFormats(); + method public int[] getOutputFormats(); method public long getOutputMinFrameDuration(int, android.util.Size); method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size); method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>); method public android.util.Size[] getOutputSizes(int); method public long getOutputStallDuration(int, android.util.Size); method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size); - method public final int[] getValidOutputFormatsForInput(int); + method public int[] getValidOutputFormatsForInput(int); method public boolean isOutputSupportedFor(int); method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>); method public boolean isOutputSupportedFor(android.view.Surface); @@ -16160,12 +16151,12 @@ package android.icu.lang { public final class UCharacter implements android.icu.lang.UCharacterEnums.ECharacterCategory android.icu.lang.UCharacterEnums.ECharacterDirection { method public static int charCount(int); - method public static final int codePointAt(java.lang.CharSequence, int); - method public static final int codePointAt(char[], int); - method public static final int codePointAt(char[], int, int); - method public static final int codePointBefore(java.lang.CharSequence, int); - method public static final int codePointBefore(char[], int); - method public static final int codePointBefore(char[], int, int); + method public static int codePointAt(java.lang.CharSequence, int); + method public static int codePointAt(char[], int); + method public static int codePointAt(char[], int, int); + method public static int codePointBefore(java.lang.CharSequence, int); + method public static int codePointBefore(char[], int); + method public static int codePointBefore(char[], int, int); method public static int codePointCount(java.lang.CharSequence, int, int); method public static int codePointCount(char[], int, int); method public static int digit(int, int); @@ -16173,7 +16164,7 @@ package android.icu.lang { method public static int foldCase(int, boolean); method public static java.lang.String foldCase(java.lang.String, boolean); method public static int foldCase(int, int); - method public static final java.lang.String foldCase(java.lang.String, int); + method public static java.lang.String foldCase(java.lang.String, int); method public static char forDigit(int, int); method public static android.icu.util.VersionInfo getAge(int); method public static int getBidiPairedBracket(int); @@ -16225,8 +16216,8 @@ package android.icu.lang { method public static boolean isPrintable(int); method public static boolean isSpaceChar(int); method public static boolean isSupplementary(int); - method public static final boolean isSupplementaryCodePoint(int); - method public static final boolean isSurrogatePair(char, char); + method public static boolean isSupplementaryCodePoint(int); + method public static boolean isSurrogatePair(char, char); method public static boolean isTitleCase(int); method public static boolean isUAlphabetic(int); method public static boolean isULowercase(int); @@ -16235,13 +16226,13 @@ package android.icu.lang { method public static boolean isUnicodeIdentifierPart(int); method public static boolean isUnicodeIdentifierStart(int); method public static boolean isUpperCase(int); - method public static final boolean isValidCodePoint(int); + method public static boolean isValidCodePoint(int); method public static boolean isWhitespace(int); method public static int offsetByCodePoints(java.lang.CharSequence, int, int); method public static int offsetByCodePoints(char[], int, int, int, int); - method public static final int toChars(int, char[], int); - method public static final char[] toChars(int); - method public static final int toCodePoint(char, char); + method public static int toChars(int, char[], int); + method public static char[] toChars(int); + method public static int toCodePoint(char, char); method public static int toLowerCase(int); method public static java.lang.String toLowerCase(java.lang.String); method public static java.lang.String toLowerCase(java.util.Locale, java.lang.String); @@ -16531,7 +16522,7 @@ package android.icu.lang { } public static final class UCharacter.UnicodeBlock extends java.lang.Character.Subset { - method public static final android.icu.lang.UCharacter.UnicodeBlock forName(java.lang.String); + method public static android.icu.lang.UCharacter.UnicodeBlock forName(java.lang.String); method public int getID(); method public static android.icu.lang.UCharacter.UnicodeBlock getInstance(int); method public static android.icu.lang.UCharacter.UnicodeBlock of(int); @@ -17338,20 +17329,20 @@ package android.icu.lang { } public final class UScript { - method public static final boolean breaksBetweenLetters(int); - method public static final int[] getCode(java.util.Locale); - method public static final int[] getCode(android.icu.util.ULocale); - method public static final int[] getCode(java.lang.String); - method public static final int getCodeFromName(java.lang.String); - method public static final java.lang.String getName(int); - method public static final java.lang.String getSampleString(int); - method public static final int getScript(int); - method public static final int getScriptExtensions(int, java.util.BitSet); - method public static final java.lang.String getShortName(int); - method public static final android.icu.lang.UScript.ScriptUsage getUsage(int); - method public static final boolean hasScript(int, int); - method public static final boolean isCased(int); - method public static final boolean isRightToLeft(int); + method public static boolean breaksBetweenLetters(int); + method public static int[] getCode(java.util.Locale); + method public static int[] getCode(android.icu.util.ULocale); + method public static int[] getCode(java.lang.String); + method public static int getCodeFromName(java.lang.String); + method public static java.lang.String getName(int); + method public static java.lang.String getSampleString(int); + method public static int getScript(int); + method public static int getScriptExtensions(int, java.util.BitSet); + method public static java.lang.String getShortName(int); + method public static android.icu.lang.UScript.ScriptUsage getUsage(int); + method public static boolean hasScript(int, int); + method public static boolean isCased(int); + method public static boolean isRightToLeft(int); field public static final int ADLAM = 167; // 0xa7 field public static final int AFAKA = 147; // 0x93 field public static final int AHOM = 161; // 0xa1 @@ -17766,14 +17757,14 @@ package android.icu.text { method public deprecated int hashCode(); method public int next(); method public int previous(); - method public static final int primaryOrder(int); + method public static int primaryOrder(int); method public void reset(); - method public static final int secondaryOrder(int); + method public static int secondaryOrder(int); method public void setOffset(int); method public void setText(java.lang.String); method public void setText(android.icu.text.UCharacterIterator); method public void setText(java.text.CharacterIterator); - method public static final int tertiaryOrder(int); + method public static int tertiaryOrder(int); field public static final int IGNORABLE = 0; // 0x0 field public static final int NULLORDER = -1; // 0xffffffff } @@ -19000,7 +18991,7 @@ package android.icu.text { method public boolean isUpperCaseFirst(); method public void setAlternateHandlingDefault(); method public void setAlternateHandlingShifted(boolean); - method public final void setCaseFirstDefault(); + method public void setCaseFirstDefault(); method public void setCaseLevel(boolean); method public void setCaseLevelDefault(); method public void setDecompositionDefault(); @@ -19973,11 +19964,11 @@ package android.icu.util { public final class LocaleData { method public static android.icu.util.VersionInfo getCLDRVersion(); method public java.lang.String getDelimiter(int); - method public static final android.icu.util.LocaleData getInstance(android.icu.util.ULocale); - method public static final android.icu.util.LocaleData getInstance(); - method public static final android.icu.util.LocaleData.MeasurementSystem getMeasurementSystem(android.icu.util.ULocale); + method public static android.icu.util.LocaleData getInstance(android.icu.util.ULocale); + method public static android.icu.util.LocaleData getInstance(); + method public static android.icu.util.LocaleData.MeasurementSystem getMeasurementSystem(android.icu.util.ULocale); method public boolean getNoSubstitute(); - method public static final android.icu.util.LocaleData.PaperSize getPaperSize(android.icu.util.ULocale); + method public static android.icu.util.LocaleData.PaperSize getPaperSize(android.icu.util.ULocale); method public void setNoSubstitute(boolean); field public static final int ALT_QUOTATION_END = 3; // 0x3 field public static final int ALT_QUOTATION_START = 2; // 0x2 @@ -22158,40 +22149,40 @@ package android.media { method public static android.media.MediaCodec createByCodecName(java.lang.String) throws java.io.IOException; method public static android.media.MediaCodec createDecoderByType(java.lang.String) throws java.io.IOException; method public static android.media.MediaCodec createEncoderByType(java.lang.String) throws java.io.IOException; - method public final android.view.Surface createInputSurface(); + method public android.view.Surface createInputSurface(); method public static android.view.Surface createPersistentInputSurface(); - method public final int dequeueInputBuffer(long); - method public final int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long); + method public int dequeueInputBuffer(long); + method public int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long); method protected void finalize(); - method public final void flush(); + method public void flush(); method public android.media.MediaCodecInfo getCodecInfo(); method public java.nio.ByteBuffer getInputBuffer(int); method public deprecated java.nio.ByteBuffer[] getInputBuffers(); - method public final android.media.MediaFormat getInputFormat(); + method public android.media.MediaFormat getInputFormat(); method public android.media.Image getInputImage(int); method public android.os.PersistableBundle getMetrics(); - method public final java.lang.String getName(); + method public java.lang.String getName(); method public java.nio.ByteBuffer getOutputBuffer(int); method public deprecated java.nio.ByteBuffer[] getOutputBuffers(); - method public final android.media.MediaFormat getOutputFormat(); - method public final android.media.MediaFormat getOutputFormat(int); + method public android.media.MediaFormat getOutputFormat(); + method public android.media.MediaFormat getOutputFormat(int); method public android.media.Image getOutputImage(int); - method public final void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException; - method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException; - method public final void release(); - method public final void releaseOutputBuffer(int, boolean); - method public final void releaseOutputBuffer(int, long); - method public final void reset(); + method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException; + method public void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException; + method public void release(); + method public void releaseOutputBuffer(int, boolean); + method public void releaseOutputBuffer(int, long); + method public void reset(); method public void setCallback(android.media.MediaCodec.Callback, android.os.Handler); method public void setCallback(android.media.MediaCodec.Callback); method public void setInputSurface(android.view.Surface); method public void setOnFrameRenderedListener(android.media.MediaCodec.OnFrameRenderedListener, android.os.Handler); method public void setOutputSurface(android.view.Surface); - method public final void setParameters(android.os.Bundle); - method public final void setVideoScalingMode(int); - method public final void signalEndOfInputStream(); - method public final void start(); - method public final void stop(); + method public void setParameters(android.os.Bundle); + method public void setVideoScalingMode(int); + method public void signalEndOfInputStream(); + method public void start(); + method public void stop(); field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2 field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4 field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1 @@ -22285,10 +22276,10 @@ package android.media { } public final class MediaCodecInfo { - method public final android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(java.lang.String); - method public final java.lang.String getName(); - method public final java.lang.String[] getSupportedTypes(); - method public final boolean isEncoder(); + method public android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(java.lang.String); + method public java.lang.String getName(); + method public java.lang.String[] getSupportedTypes(); + method public boolean isEncoder(); } public static final class MediaCodecInfo.AudioCapabilities { @@ -22308,9 +22299,9 @@ package android.media { method public int getMaxSupportedInstances(); method public java.lang.String getMimeType(); method public android.media.MediaCodecInfo.VideoCapabilities getVideoCapabilities(); - method public final boolean isFeatureRequired(java.lang.String); - method public final boolean isFeatureSupported(java.lang.String); - method public final boolean isFormatSupported(android.media.MediaFormat); + method public boolean isFeatureRequired(java.lang.String); + method public boolean isFeatureSupported(java.lang.String); + method public boolean isFormatSupported(android.media.MediaFormat); field public static final deprecated int COLOR_Format12bitRGB444 = 3; // 0x3 field public static final deprecated int COLOR_Format16bitARGB1555 = 5; // 0x5 field public static final deprecated int COLOR_Format16bitARGB4444 = 4; // 0x4 @@ -22567,11 +22558,11 @@ package android.media { public final class MediaCodecList { ctor public MediaCodecList(int); - method public final java.lang.String findDecoderForFormat(android.media.MediaFormat); - method public final java.lang.String findEncoderForFormat(android.media.MediaFormat); - method public static final deprecated int getCodecCount(); - method public static final deprecated android.media.MediaCodecInfo getCodecInfoAt(int); - method public final android.media.MediaCodecInfo[] getCodecInfos(); + method public java.lang.String findDecoderForFormat(android.media.MediaFormat); + method public java.lang.String findEncoderForFormat(android.media.MediaFormat); + method public static deprecated int getCodecCount(); + method public static deprecated android.media.MediaCodecInfo getCodecInfoAt(int); + method public android.media.MediaCodecInfo[] getCodecInfos(); field public static final int ALL_CODECS = 1; // 0x1 field public static final int REGULAR_CODECS = 0; // 0x0 } @@ -22579,10 +22570,10 @@ package android.media { public final class MediaCrypto { ctor public MediaCrypto(java.util.UUID, byte[]) throws android.media.MediaCryptoException; method protected void finalize(); - method public static final boolean isCryptoSchemeSupported(java.util.UUID); - method public final void release(); - method public final boolean requiresSecureDecoderComponent(java.lang.String); - method public final void setMediaDrmSession(byte[]) throws android.media.MediaCryptoException; + method public static boolean isCryptoSchemeSupported(java.util.UUID); + method public void release(); + method public boolean requiresSecureDecoderComponent(java.lang.String); + method public void setMediaDrmSession(byte[]) throws android.media.MediaCryptoException; } public final class MediaCryptoException extends java.lang.Exception { @@ -22598,10 +22589,10 @@ package android.media { public final class MediaDescrambler implements java.lang.AutoCloseable { ctor public MediaDescrambler(int) throws android.media.MediaCasException.UnsupportedCasException; method public void close(); - method public final int descramble(java.nio.ByteBuffer, java.nio.ByteBuffer, android.media.MediaCodec.CryptoInfo); + method public int descramble(java.nio.ByteBuffer, java.nio.ByteBuffer, android.media.MediaCodec.CryptoInfo); method protected void finalize(); - method public final boolean requiresSecureDecoderComponent(java.lang.String); - method public final void setMediaCasSession(android.media.MediaCas.Session); + method public boolean requiresSecureDecoderComponent(java.lang.String); + method public void setMediaCasSession(android.media.MediaCas.Session); } public class MediaDescription implements android.os.Parcelable { @@ -22650,13 +22641,13 @@ package android.media { method public android.media.MediaDrm.ProvisionRequest getProvisionRequest(); method public byte[] getSecureStop(byte[]); method public java.util.List<byte[]> getSecureStops(); - method public static final boolean isCryptoSchemeSupported(java.util.UUID); - method public static final boolean isCryptoSchemeSupported(java.util.UUID, java.lang.String); + method public static boolean isCryptoSchemeSupported(java.util.UUID); + method public static boolean isCryptoSchemeSupported(java.util.UUID, java.lang.String); method public byte[] openSession() throws android.media.NotProvisionedException, android.media.ResourceBusyException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.NotProvisionedException; method public void provideProvisionResponse(byte[]) throws android.media.DeniedByServerException; method public java.util.HashMap<java.lang.String, java.lang.String> queryKeyStatus(byte[]); - method public final void release(); + method public void release(); method public void releaseAllSecureStops(); method public void releaseSecureStops(byte[]); method public void removeKeys(byte[]); @@ -22749,21 +22740,21 @@ package android.media { method public int getSampleFlags(); method public long getSampleTime(); method public int getSampleTrackIndex(); - method public final int getTrackCount(); + method public int getTrackCount(); method public android.media.MediaFormat getTrackFormat(int); method public boolean hasCacheReachedEndOfStream(); method public int readSampleData(java.nio.ByteBuffer, int); - method public final void release(); + method public void release(); method public void seekTo(long, int); method public void selectTrack(int); - method public final void setDataSource(android.media.MediaDataSource) throws java.io.IOException; - method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException; - method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException; - method public final void setDataSource(java.lang.String) throws java.io.IOException; - method public final void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; - method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException; - method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException; - method public final void setMediaCas(android.media.MediaCas); + method public void setDataSource(android.media.MediaDataSource) throws java.io.IOException; + method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException; + method public void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException; + method public void setDataSource(java.lang.String) throws java.io.IOException; + method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; + method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException; + method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException; + method public void setMediaCas(android.media.MediaCas); method public void unselectTrack(int); field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2 field public static final int SAMPLE_FLAG_PARTIAL_FRAME = 4; // 0x4 @@ -22786,22 +22777,22 @@ package android.media { public final class MediaFormat { ctor public MediaFormat(); - method public final boolean containsKey(java.lang.String); - method public static final android.media.MediaFormat createAudioFormat(java.lang.String, int, int); - method public static final android.media.MediaFormat createSubtitleFormat(java.lang.String, java.lang.String); - method public static final android.media.MediaFormat createVideoFormat(java.lang.String, int, int); - method public final java.nio.ByteBuffer getByteBuffer(java.lang.String); + method public boolean containsKey(java.lang.String); + method public static android.media.MediaFormat createAudioFormat(java.lang.String, int, int); + method public static android.media.MediaFormat createSubtitleFormat(java.lang.String, java.lang.String); + method public static android.media.MediaFormat createVideoFormat(java.lang.String, int, int); + method public java.nio.ByteBuffer getByteBuffer(java.lang.String); method public boolean getFeatureEnabled(java.lang.String); - method public final float getFloat(java.lang.String); - method public final int getInteger(java.lang.String); - method public final long getLong(java.lang.String); - method public final java.lang.String getString(java.lang.String); - method public final void setByteBuffer(java.lang.String, java.nio.ByteBuffer); + method public float getFloat(java.lang.String); + method public int getInteger(java.lang.String); + method public long getLong(java.lang.String); + method public java.lang.String getString(java.lang.String); + method public void setByteBuffer(java.lang.String, java.nio.ByteBuffer); method public void setFeatureEnabled(java.lang.String, boolean); - method public final void setFloat(java.lang.String, float); - method public final void setInteger(java.lang.String, int); - method public final void setLong(java.lang.String, long); - method public final void setString(java.lang.String, java.lang.String); + method public void setFloat(java.lang.String, float); + method public void setInteger(java.lang.String, int); + method public void setLong(java.lang.String, long); + method public void setString(java.lang.String, java.lang.String); field public static final int COLOR_RANGE_FULL = 1; // 0x1 field public static final int COLOR_RANGE_LIMITED = 2; // 0x2 field public static final int COLOR_STANDARD_BT2020 = 6; // 0x6 @@ -23508,14 +23499,14 @@ package android.media { public final class MediaSync { ctor public MediaSync(); - method public final android.view.Surface createInputSurface(); + method public android.view.Surface createInputSurface(); method protected void finalize(); method public void flush(); method public android.media.PlaybackParams getPlaybackParams(); method public android.media.SyncParams getSyncParams(); method public android.media.MediaTimestamp getTimestamp(); method public void queueAudio(java.nio.ByteBuffer, int, long); - method public final void release(); + method public void release(); method public void setAudioTrack(android.media.AudioTrack); method public void setCallback(android.media.MediaSync.Callback, android.os.Handler); method public void setOnErrorListener(android.media.MediaSync.OnErrorListener, android.os.Handler); @@ -24470,7 +24461,7 @@ package android.media.midi { public final class MidiInputPort extends android.media.midi.MidiReceiver implements java.io.Closeable { method public void close() throws java.io.IOException; - method public final int getPortNumber(); + method public int getPortNumber(); method public void onSend(byte[], int, int, long) throws java.io.IOException; } @@ -24495,7 +24486,7 @@ package android.media.midi { public final class MidiOutputPort extends android.media.midi.MidiSender implements java.io.Closeable { method public void close() throws java.io.IOException; - method public final int getPortNumber(); + method public int getPortNumber(); method public void onConnect(android.media.midi.MidiReceiver); method public void onDisconnect(android.media.midi.MidiReceiver); } @@ -24770,7 +24761,7 @@ package android.media.session { package android.media.tv { public final class TvContentRating { - method public final boolean contains(android.media.tv.TvContentRating); + method public boolean contains(android.media.tv.TvContentRating); method public static android.media.tv.TvContentRating createRating(java.lang.String, java.lang.String, java.lang.String, java.lang.String...); method public java.lang.String flattenToString(); method public java.lang.String getDomain(); @@ -24820,7 +24811,7 @@ package android.media.tv { } public static final class TvContract.Channels implements android.media.tv.TvContract.BaseTvColumns { - method public static final java.lang.String getVideoResolution(java.lang.String); + method public static java.lang.String getVideoResolution(java.lang.String); field public static final java.lang.String COLUMN_APP_LINK_COLOR = "app_link_color"; field public static final java.lang.String COLUMN_APP_LINK_ICON_URI = "app_link_icon_uri"; field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri"; @@ -25344,18 +25335,18 @@ package android.media.tv { public final class TvTrackInfo implements android.os.Parcelable { method public int describeContents(); - method public final int getAudioChannelCount(); - method public final int getAudioSampleRate(); - method public final java.lang.CharSequence getDescription(); - method public final android.os.Bundle getExtra(); - method public final java.lang.String getId(); - method public final java.lang.String getLanguage(); - method public final int getType(); - method public final byte getVideoActiveFormatDescription(); - method public final float getVideoFrameRate(); - method public final int getVideoHeight(); - method public final float getVideoPixelAspectRatio(); - method public final int getVideoWidth(); + method public int getAudioChannelCount(); + method public int getAudioSampleRate(); + method public java.lang.CharSequence getDescription(); + method public android.os.Bundle getExtra(); + method public java.lang.String getId(); + method public java.lang.String getLanguage(); + method public int getType(); + method public byte getVideoActiveFormatDescription(); + method public float getVideoFrameRate(); + method public int getVideoHeight(); + method public float getVideoPixelAspectRatio(); + method public int getVideoWidth(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.media.tv.TvTrackInfo> CREATOR; field public static final int TYPE_AUDIO = 0; // 0x0 @@ -25366,16 +25357,16 @@ package android.media.tv { public static final class TvTrackInfo.Builder { ctor public TvTrackInfo.Builder(int, java.lang.String); method public android.media.tv.TvTrackInfo build(); - method public final android.media.tv.TvTrackInfo.Builder setAudioChannelCount(int); - method public final android.media.tv.TvTrackInfo.Builder setAudioSampleRate(int); - method public final android.media.tv.TvTrackInfo.Builder setDescription(java.lang.CharSequence); - method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle); - method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String); - method public final android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte); - method public final android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float); - method public final android.media.tv.TvTrackInfo.Builder setVideoHeight(int); - method public final android.media.tv.TvTrackInfo.Builder setVideoPixelAspectRatio(float); - method public final android.media.tv.TvTrackInfo.Builder setVideoWidth(int); + method public android.media.tv.TvTrackInfo.Builder setAudioChannelCount(int); + method public android.media.tv.TvTrackInfo.Builder setAudioSampleRate(int); + method public android.media.tv.TvTrackInfo.Builder setDescription(java.lang.CharSequence); + method public android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle); + method public android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String); + method public android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte); + method public android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float); + method public android.media.tv.TvTrackInfo.Builder setVideoHeight(int); + method public android.media.tv.TvTrackInfo.Builder setVideoPixelAspectRatio(float); + method public android.media.tv.TvTrackInfo.Builder setVideoWidth(int); } public class TvView extends android.view.ViewGroup { @@ -25606,34 +25597,34 @@ package android.mtp { } public final class MtpObjectInfo { - method public final int getAssociationDesc(); - method public final int getAssociationType(); - method public final int getCompressedSize(); - method public final long getCompressedSizeLong(); - method public final long getDateCreated(); - method public final long getDateModified(); - method public final int getFormat(); - method public final int getImagePixDepth(); - method public final long getImagePixDepthLong(); - method public final int getImagePixHeight(); - method public final long getImagePixHeightLong(); - method public final int getImagePixWidth(); - method public final long getImagePixWidthLong(); - method public final java.lang.String getKeywords(); - method public final java.lang.String getName(); - method public final int getObjectHandle(); - method public final int getParent(); - method public final int getProtectionStatus(); - method public final int getSequenceNumber(); - method public final long getSequenceNumberLong(); - method public final int getStorageId(); - method public final int getThumbCompressedSize(); - method public final long getThumbCompressedSizeLong(); - method public final int getThumbFormat(); - method public final int getThumbPixHeight(); - method public final long getThumbPixHeightLong(); - method public final int getThumbPixWidth(); - method public final long getThumbPixWidthLong(); + method public int getAssociationDesc(); + method public int getAssociationType(); + method public int getCompressedSize(); + method public long getCompressedSizeLong(); + method public long getDateCreated(); + method public long getDateModified(); + method public int getFormat(); + method public int getImagePixDepth(); + method public long getImagePixDepthLong(); + method public int getImagePixHeight(); + method public long getImagePixHeightLong(); + method public int getImagePixWidth(); + method public long getImagePixWidthLong(); + method public java.lang.String getKeywords(); + method public java.lang.String getName(); + method public int getObjectHandle(); + method public int getParent(); + method public int getProtectionStatus(); + method public int getSequenceNumber(); + method public long getSequenceNumberLong(); + method public int getStorageId(); + method public int getThumbCompressedSize(); + method public long getThumbCompressedSizeLong(); + method public int getThumbFormat(); + method public int getThumbPixHeight(); + method public long getThumbPixHeightLong(); + method public int getThumbPixWidth(); + method public long getThumbPixWidthLong(); } public static class MtpObjectInfo.Builder { @@ -25663,11 +25654,11 @@ package android.mtp { } public final class MtpStorageInfo { - method public final java.lang.String getDescription(); - method public final long getFreeSpace(); - method public final long getMaxCapacity(); - method public final int getStorageId(); - method public final java.lang.String getVolumeIdentifier(); + method public java.lang.String getDescription(); + method public long getFreeSpace(); + method public long getMaxCapacity(); + method public int getStorageId(); + method public java.lang.String getVolumeIdentifier(); } } @@ -25725,7 +25716,7 @@ package android.net { field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; field public static final java.lang.String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL"; field public static final java.lang.String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED"; - field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; + field public static final deprecated java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1 field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL"; field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; @@ -26001,6 +25992,7 @@ package android.net { field public static final int NET_CAPABILITY_CBS = 5; // 0x5 field public static final int NET_CAPABILITY_DUN = 2; // 0x2 field public static final int NET_CAPABILITY_EIMS = 10; // 0xa + field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13 field public static final int NET_CAPABILITY_FOTA = 3; // 0x3 field public static final int NET_CAPABILITY_IA = 7; // 0x7 field public static final int NET_CAPABILITY_IMS = 4; // 0x4 @@ -26009,6 +26001,7 @@ package android.net { field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12 + field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15 field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf field public static final int NET_CAPABILITY_RCS = 8; // 0x8 field public static final int NET_CAPABILITY_SUPL = 1; // 0x1 @@ -26099,10 +26092,10 @@ package android.net { public final class Proxy { ctor public Proxy(); - method public static final deprecated java.lang.String getDefaultHost(); - method public static final deprecated int getDefaultPort(); - method public static final deprecated java.lang.String getHost(android.content.Context); - method public static final deprecated int getPort(android.content.Context); + method public static deprecated java.lang.String getDefaultHost(); + method public static deprecated int getDefaultPort(); + method public static deprecated java.lang.String getHost(android.content.Context); + method public static deprecated int getPort(android.content.Context); field public static final deprecated java.lang.String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO"; field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE"; } @@ -31051,9 +31044,9 @@ package android.os { method public static void dumpHprofData(java.lang.String) throws java.io.IOException; method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]); method public static void enableEmulatorTraceOutput(); - method public static final int getBinderDeathObjectCount(); - method public static final int getBinderLocalObjectCount(); - method public static final int getBinderProxyObjectCount(); + method public static int getBinderDeathObjectCount(); + method public static int getBinderLocalObjectCount(); + method public static int getBinderProxyObjectCount(); method public static int getBinderReceivedTransactions(); method public static int getBinderSentTransactions(); method public static deprecated int getGlobalAllocCount(); @@ -31461,114 +31454,114 @@ package android.os { } public final class Parcel { - method public final void appendFrom(android.os.Parcel, int, int); - method public final android.os.IBinder[] createBinderArray(); - method public final java.util.ArrayList<android.os.IBinder> createBinderArrayList(); - method public final boolean[] createBooleanArray(); - method public final byte[] createByteArray(); - method public final char[] createCharArray(); - method public final double[] createDoubleArray(); - method public final float[] createFloatArray(); - method public final int[] createIntArray(); - method public final long[] createLongArray(); - method public final java.lang.String[] createStringArray(); - method public final java.util.ArrayList<java.lang.String> createStringArrayList(); - method public final <T> T[] createTypedArray(android.os.Parcelable.Creator<T>); - method public final <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>); - method public final int dataAvail(); - method public final int dataCapacity(); - method public final int dataPosition(); - method public final int dataSize(); - method public final void enforceInterface(java.lang.String); - method public final boolean hasFileDescriptors(); - method public final byte[] marshall(); + method public void appendFrom(android.os.Parcel, int, int); + method public android.os.IBinder[] createBinderArray(); + method public java.util.ArrayList<android.os.IBinder> createBinderArrayList(); + method public boolean[] createBooleanArray(); + method public byte[] createByteArray(); + method public char[] createCharArray(); + method public double[] createDoubleArray(); + method public float[] createFloatArray(); + method public int[] createIntArray(); + method public long[] createLongArray(); + method public java.lang.String[] createStringArray(); + method public java.util.ArrayList<java.lang.String> createStringArrayList(); + method public <T> T[] createTypedArray(android.os.Parcelable.Creator<T>); + method public <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>); + method public int dataAvail(); + method public int dataCapacity(); + method public int dataPosition(); + method public int dataSize(); + method public void enforceInterface(java.lang.String); + method public boolean hasFileDescriptors(); + method public byte[] marshall(); method public static android.os.Parcel obtain(); - method public final java.lang.Object[] readArray(java.lang.ClassLoader); - method public final java.util.ArrayList readArrayList(java.lang.ClassLoader); - method public final void readBinderArray(android.os.IBinder[]); - method public final void readBinderList(java.util.List<android.os.IBinder>); - method public final void readBooleanArray(boolean[]); - method public final android.os.Bundle readBundle(); - method public final android.os.Bundle readBundle(java.lang.ClassLoader); - method public final byte readByte(); - method public final void readByteArray(byte[]); - method public final void readCharArray(char[]); - method public final double readDouble(); - method public final void readDoubleArray(double[]); - method public final void readException(); - method public final void readException(int, java.lang.String); - method public final android.os.ParcelFileDescriptor readFileDescriptor(); - method public final float readFloat(); - method public final void readFloatArray(float[]); - method public final java.util.HashMap readHashMap(java.lang.ClassLoader); - method public final int readInt(); - method public final void readIntArray(int[]); - method public final void readList(java.util.List, java.lang.ClassLoader); - method public final long readLong(); - method public final void readLongArray(long[]); - method public final void readMap(java.util.Map, java.lang.ClassLoader); - method public final <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader); - method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader); - method public final android.os.PersistableBundle readPersistableBundle(); - method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader); - method public final java.io.Serializable readSerializable(); - method public final android.util.Size readSize(); - method public final android.util.SizeF readSizeF(); - method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader); - method public final android.util.SparseBooleanArray readSparseBooleanArray(); - method public final java.lang.String readString(); - method public final void readStringArray(java.lang.String[]); - method public final void readStringList(java.util.List<java.lang.String>); - method public final android.os.IBinder readStrongBinder(); - method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>); - method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>); - method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>); - method public final java.lang.Object readValue(java.lang.ClassLoader); - method public final void recycle(); - method public final void setDataCapacity(int); - method public final void setDataPosition(int); - method public final void setDataSize(int); - method public final void unmarshall(byte[], int, int); - method public final void writeArray(java.lang.Object[]); - method public final void writeBinderArray(android.os.IBinder[]); - method public final void writeBinderList(java.util.List<android.os.IBinder>); - method public final void writeBooleanArray(boolean[]); - method public final void writeBundle(android.os.Bundle); - method public final void writeByte(byte); - method public final void writeByteArray(byte[]); - method public final void writeByteArray(byte[], int, int); - method public final void writeCharArray(char[]); - method public final void writeDouble(double); - method public final void writeDoubleArray(double[]); - method public final void writeException(java.lang.Exception); - method public final void writeFileDescriptor(java.io.FileDescriptor); - method public final void writeFloat(float); - method public final void writeFloatArray(float[]); - method public final void writeInt(int); - method public final void writeIntArray(int[]); - method public final void writeInterfaceToken(java.lang.String); - method public final void writeList(java.util.List); - method public final void writeLong(long); - method public final void writeLongArray(long[]); - method public final void writeMap(java.util.Map); - method public final void writeNoException(); - method public final void writeParcelable(android.os.Parcelable, int); - method public final <T extends android.os.Parcelable> void writeParcelableArray(T[], int); - method public final void writePersistableBundle(android.os.PersistableBundle); - method public final void writeSerializable(java.io.Serializable); - method public final void writeSize(android.util.Size); - method public final void writeSizeF(android.util.SizeF); - method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>); - method public final void writeSparseBooleanArray(android.util.SparseBooleanArray); - method public final void writeString(java.lang.String); - method public final void writeStringArray(java.lang.String[]); - method public final void writeStringList(java.util.List<java.lang.String>); - method public final void writeStrongBinder(android.os.IBinder); - method public final void writeStrongInterface(android.os.IInterface); - method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int); - method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>); - method public final <T extends android.os.Parcelable> void writeTypedObject(T, int); - method public final void writeValue(java.lang.Object); + method public java.lang.Object[] readArray(java.lang.ClassLoader); + method public java.util.ArrayList readArrayList(java.lang.ClassLoader); + method public void readBinderArray(android.os.IBinder[]); + method public void readBinderList(java.util.List<android.os.IBinder>); + method public void readBooleanArray(boolean[]); + method public android.os.Bundle readBundle(); + method public android.os.Bundle readBundle(java.lang.ClassLoader); + method public byte readByte(); + method public void readByteArray(byte[]); + method public void readCharArray(char[]); + method public double readDouble(); + method public void readDoubleArray(double[]); + method public void readException(); + method public void readException(int, java.lang.String); + method public android.os.ParcelFileDescriptor readFileDescriptor(); + method public float readFloat(); + method public void readFloatArray(float[]); + method public java.util.HashMap readHashMap(java.lang.ClassLoader); + method public int readInt(); + method public void readIntArray(int[]); + method public void readList(java.util.List, java.lang.ClassLoader); + method public long readLong(); + method public void readLongArray(long[]); + method public void readMap(java.util.Map, java.lang.ClassLoader); + method public <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader); + method public android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader); + method public android.os.PersistableBundle readPersistableBundle(); + method public android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader); + method public java.io.Serializable readSerializable(); + method public android.util.Size readSize(); + method public android.util.SizeF readSizeF(); + method public android.util.SparseArray readSparseArray(java.lang.ClassLoader); + method public android.util.SparseBooleanArray readSparseBooleanArray(); + method public java.lang.String readString(); + method public void readStringArray(java.lang.String[]); + method public void readStringList(java.util.List<java.lang.String>); + method public android.os.IBinder readStrongBinder(); + method public <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>); + method public <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>); + method public <T> T readTypedObject(android.os.Parcelable.Creator<T>); + method public java.lang.Object readValue(java.lang.ClassLoader); + method public void recycle(); + method public void setDataCapacity(int); + method public void setDataPosition(int); + method public void setDataSize(int); + method public void unmarshall(byte[], int, int); + method public void writeArray(java.lang.Object[]); + method public void writeBinderArray(android.os.IBinder[]); + method public void writeBinderList(java.util.List<android.os.IBinder>); + method public void writeBooleanArray(boolean[]); + method public void writeBundle(android.os.Bundle); + method public void writeByte(byte); + method public void writeByteArray(byte[]); + method public void writeByteArray(byte[], int, int); + method public void writeCharArray(char[]); + method public void writeDouble(double); + method public void writeDoubleArray(double[]); + method public void writeException(java.lang.Exception); + method public void writeFileDescriptor(java.io.FileDescriptor); + method public void writeFloat(float); + method public void writeFloatArray(float[]); + method public void writeInt(int); + method public void writeIntArray(int[]); + method public void writeInterfaceToken(java.lang.String); + method public void writeList(java.util.List); + method public void writeLong(long); + method public void writeLongArray(long[]); + method public void writeMap(java.util.Map); + method public void writeNoException(); + method public void writeParcelable(android.os.Parcelable, int); + method public <T extends android.os.Parcelable> void writeParcelableArray(T[], int); + method public void writePersistableBundle(android.os.PersistableBundle); + method public void writeSerializable(java.io.Serializable); + method public void writeSize(android.util.Size); + method public void writeSizeF(android.util.SizeF); + method public void writeSparseArray(android.util.SparseArray<java.lang.Object>); + method public void writeSparseBooleanArray(android.util.SparseBooleanArray); + method public void writeString(java.lang.String); + method public void writeStringArray(java.lang.String[]); + method public void writeStringList(java.util.List<java.lang.String>); + method public void writeStrongBinder(android.os.IBinder); + method public void writeStrongInterface(android.os.IInterface); + method public <T extends android.os.Parcelable> void writeTypedArray(T[], int); + method public <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>); + method public <T extends android.os.Parcelable> void writeTypedObject(T, int); + method public void writeValue(java.lang.Object); field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR; } @@ -33135,7 +33128,7 @@ package android.provider { } public static final class CalendarContract.Attendees implements android.provider.BaseColumns android.provider.CalendarContract.AttendeesColumns android.provider.CalendarContract.EventsColumns { - method public static final android.database.Cursor query(android.content.ContentResolver, long, java.lang.String[]); + method public static android.database.Cursor query(android.content.ContentResolver, long, java.lang.String[]); field public static final android.net.Uri CONTENT_URI; } @@ -33264,7 +33257,7 @@ package android.provider { } public static final class CalendarContract.EventDays implements android.provider.CalendarContract.EventDaysColumns { - method public static final android.database.Cursor query(android.content.ContentResolver, int, int, java.lang.String[]); + method public static android.database.Cursor query(android.content.ContentResolver, int, int, java.lang.String[]); field public static final android.net.Uri CONTENT_URI; } @@ -33357,8 +33350,8 @@ package android.provider { } public static final class CalendarContract.Instances implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.EventsColumns { - method public static final android.database.Cursor query(android.content.ContentResolver, java.lang.String[], long, long); - method public static final android.database.Cursor query(android.content.ContentResolver, java.lang.String[], long, long, java.lang.String); + method public static android.database.Cursor query(android.content.ContentResolver, java.lang.String[], long, long); + method public static android.database.Cursor query(android.content.ContentResolver, java.lang.String[], long, long, java.lang.String); field public static final java.lang.String BEGIN = "begin"; field public static final android.net.Uri CONTENT_BY_DAY_URI; field public static final android.net.Uri CONTENT_SEARCH_BY_DAY_URI; @@ -33373,7 +33366,7 @@ package android.provider { } public static final class CalendarContract.Reminders implements android.provider.BaseColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.RemindersColumns { - method public static final android.database.Cursor query(android.content.ContentResolver, long, java.lang.String[]); + method public static android.database.Cursor query(android.content.ContentResolver, long, java.lang.String[]); field public static final android.net.Uri CONTENT_URI; } @@ -33481,7 +33474,7 @@ package android.provider { method public static deprecated java.lang.Object decodeImProtocol(java.lang.String); method public static deprecated java.lang.String encodeCustomImProtocol(java.lang.String); method public static deprecated java.lang.String encodePredefinedImProtocol(int); - method public static final deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, int, java.lang.CharSequence); + method public static deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, int, java.lang.CharSequence); field public static final deprecated java.lang.String CONTENT_EMAIL_ITEM_TYPE = "vnd.android.cursor.item/email"; field public static final deprecated java.lang.String CONTENT_EMAIL_TYPE = "vnd.android.cursor.dir/email"; field public static final deprecated android.net.Uri CONTENT_EMAIL_URI; @@ -33631,7 +33624,7 @@ package android.provider { } public static final deprecated class Contacts.Organizations implements android.provider.BaseColumns android.provider.Contacts.OrganizationColumns { - method public static final deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, java.lang.CharSequence); + method public static deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, java.lang.CharSequence); field public static final deprecated java.lang.String CONTENT_DIRECTORY = "organizations"; field public static final deprecated android.net.Uri CONTENT_URI; field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "company, title, isprimary ASC"; @@ -33688,8 +33681,8 @@ package android.provider { } public static final deprecated class Contacts.Phones implements android.provider.BaseColumns android.provider.Contacts.PeopleColumns android.provider.Contacts.PhonesColumns { - method public static final deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, java.lang.CharSequence, java.lang.CharSequence[]); - method public static final deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, java.lang.CharSequence); + method public static deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, java.lang.CharSequence, java.lang.CharSequence[]); + method public static deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, java.lang.CharSequence); field public static final deprecated android.net.Uri CONTENT_FILTER_URL; field public static final deprecated java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone"; field public static final deprecated java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/phone"; @@ -33829,8 +33822,8 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Email implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { - method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); - method public static final int getTypeLabelResource(int); + method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); + method public static int getTypeLabelResource(int); field public static final java.lang.String ADDRESS = "data1"; field public static final android.net.Uri CONTENT_FILTER_URI; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2"; @@ -33850,7 +33843,7 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Event implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { - method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); + method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); method public static int getTypeResource(java.lang.Integer); field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_event"; field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; @@ -33881,10 +33874,10 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Im implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { - method public static final java.lang.CharSequence getProtocolLabel(android.content.res.Resources, int, java.lang.CharSequence); - method public static final int getProtocolLabelResource(int); - method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); - method public static final int getTypeLabelResource(int); + method public static java.lang.CharSequence getProtocolLabel(android.content.res.Resources, int, java.lang.CharSequence); + method public static int getProtocolLabelResource(int); + method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); + method public static int getTypeLabelResource(int); field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im"; field public static final java.lang.String CUSTOM_PROTOCOL = "data6"; field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; @@ -33929,8 +33922,8 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Organization implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { - method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); - method public static final int getTypeLabelResource(int); + method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); + method public static int getTypeLabelResource(int); field public static final java.lang.String COMPANY = "data1"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization"; field public static final java.lang.String DEPARTMENT = "data5"; @@ -33948,8 +33941,8 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Phone implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { - method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); - method public static final int getTypeLabelResource(int); + method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); + method public static int getTypeLabelResource(int); field public static final android.net.Uri CONTENT_FILTER_URI; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2"; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/phone_v2"; @@ -33994,8 +33987,8 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Relation implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { - method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); - method public static final int getTypeLabelResource(int); + method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); + method public static int getTypeLabelResource(int); field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation"; field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; @@ -34018,8 +34011,8 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.SipAddress implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { - method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); - method public static final int getTypeLabelResource(int); + method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); + method public static int getTypeLabelResource(int); field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sip_address"; field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; @@ -34049,8 +34042,8 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.StructuredPostal implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { - method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); - method public static final int getTypeLabelResource(int); + method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); + method public static int getTypeLabelResource(int); field public static final java.lang.String CITY = "data7"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/postal-address_v2"; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/postal-address_v2"; @@ -34875,7 +34868,7 @@ package android.provider { public static final class MediaStore.Audio.Artists.Albums implements android.provider.MediaStore.Audio.AlbumColumns { ctor public MediaStore.Audio.Artists.Albums(); - method public static final android.net.Uri getContentUri(java.lang.String, long); + method public static android.net.Uri getContentUri(java.lang.String, long); } public static abstract interface MediaStore.Audio.AudioColumns implements android.provider.MediaStore.MediaColumns { @@ -34911,7 +34904,7 @@ package android.provider { public static final class MediaStore.Audio.Genres.Members implements android.provider.MediaStore.Audio.AudioColumns { ctor public MediaStore.Audio.Genres.Members(); - method public static final android.net.Uri getContentUri(java.lang.String, long); + method public static android.net.Uri getContentUri(java.lang.String, long); field public static final java.lang.String AUDIO_ID = "audio_id"; field public static final java.lang.String CONTENT_DIRECTORY = "members"; field public static final java.lang.String DEFAULT_SORT_ORDER = "title_key"; @@ -34947,8 +34940,8 @@ package android.provider { public static final class MediaStore.Audio.Playlists.Members implements android.provider.MediaStore.Audio.AudioColumns { ctor public MediaStore.Audio.Playlists.Members(); - method public static final android.net.Uri getContentUri(java.lang.String, long); - method public static final boolean moveItem(android.content.ContentResolver, long, int, int); + method public static android.net.Uri getContentUri(java.lang.String, long); + method public static boolean moveItem(android.content.ContentResolver, long, int, int); field public static final java.lang.String AUDIO_ID = "audio_id"; field public static final java.lang.String CONTENT_DIRECTORY = "members"; field public static final java.lang.String DEFAULT_SORT_ORDER = "play_order"; @@ -34971,7 +34964,7 @@ package android.provider { public static final class MediaStore.Files { ctor public MediaStore.Files(); method public static android.net.Uri getContentUri(java.lang.String); - method public static final android.net.Uri getContentUri(java.lang.String, long); + method public static android.net.Uri getContentUri(java.lang.String, long); } public static abstract interface MediaStore.Files.FileColumns implements android.provider.MediaStore.MediaColumns { @@ -35005,13 +34998,13 @@ package android.provider { public static final class MediaStore.Images.Media implements android.provider.MediaStore.Images.ImageColumns { ctor public MediaStore.Images.Media(); - method public static final android.graphics.Bitmap getBitmap(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException, java.io.IOException; + method public static android.graphics.Bitmap getBitmap(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException, java.io.IOException; method public static android.net.Uri getContentUri(java.lang.String); - method public static final java.lang.String insertImage(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException; - method public static final java.lang.String insertImage(android.content.ContentResolver, android.graphics.Bitmap, java.lang.String, java.lang.String); - method public static final android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[]); - method public static final android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String); - method public static final android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String); + method public static java.lang.String insertImage(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException; + method public static java.lang.String insertImage(android.content.ContentResolver, android.graphics.Bitmap, java.lang.String, java.lang.String); + method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[]); + method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String); + method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String); field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/image"; field public static final java.lang.String DEFAULT_SORT_ORDER = "bucket_display_name"; field public static final android.net.Uri EXTERNAL_CONTENT_URI; @@ -35056,7 +35049,7 @@ package android.provider { public static final class MediaStore.Video { ctor public MediaStore.Video(); - method public static final android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[]); + method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[]); field public static final java.lang.String DEFAULT_SORT_ORDER = "_display_name"; } @@ -35285,12 +35278,12 @@ package android.provider { method public static long getLong(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException; method public static java.lang.String getString(android.content.ContentResolver, java.lang.String); method public static android.net.Uri getUriFor(java.lang.String); - method public static final deprecated boolean isLocationProviderEnabled(android.content.ContentResolver, java.lang.String); + method public static deprecated boolean isLocationProviderEnabled(android.content.ContentResolver, java.lang.String); method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float); method public static boolean putInt(android.content.ContentResolver, java.lang.String, int); method public static boolean putLong(android.content.ContentResolver, java.lang.String, long); method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String); - method public static final deprecated void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean); + method public static deprecated void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean); field public static final java.lang.String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled"; field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled"; field public static final deprecated java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password"; @@ -35560,6 +35553,13 @@ package android.provider { field public static final java.lang.String ADDRESS = "address"; } + public static final class Telephony.CarrierIdentification implements android.provider.BaseColumns { + method public static android.net.Uri getUriForSubscriptionId(int); + field public static final java.lang.String CID = "carrier_id"; + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String NAME = "carrier_name"; + } + public static final class Telephony.Carriers implements android.provider.BaseColumns { field public static final java.lang.String APN = "apn"; field public static final java.lang.String AUTH_TYPE = "authtype"; @@ -39129,6 +39129,7 @@ package android.telecom { public final class Call { method public void answer(int); method public void conference(android.telecom.Call); + method public void deflect(android.net.Uri); method public void disconnect(); method public java.util.List<java.lang.String> getCannedTextResponses(); method public java.util.List<android.telecom.Call> getChildren(); @@ -39147,12 +39148,12 @@ package android.telecom { method public void playDtmfTone(char); method public void postDialContinue(boolean); method public void pullExternalCall(); - method public final void putExtras(android.os.Bundle); + method public void putExtras(android.os.Bundle); method public void registerCallback(android.telecom.Call.Callback); method public void registerCallback(android.telecom.Call.Callback, android.os.Handler); method public void reject(boolean, java.lang.String); - method public final void removeExtras(java.util.List<java.lang.String>); - method public final void removeExtras(java.lang.String...); + method public void removeExtras(java.util.List<java.lang.String>); + method public void removeExtras(java.lang.String...); method public void respondToRttRequest(int, boolean); method public void sendCallEvent(java.lang.String, android.os.Bundle); method public void sendRttRequest(); @@ -39239,6 +39240,7 @@ package android.telecom { field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 3072; // 0xc00 field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 1024; // 0x400 field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800 + field public static final int CAPABILITY_SUPPORT_DEFLECT = 16777216; // 0x1000000 field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2 field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8 field public static final int PROPERTY_CONFERENCE = 1; // 0x1 @@ -39341,8 +39343,8 @@ package android.telecom { method public final void setActive(); method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>); method public final void setConnectionCapabilities(int); - method public final void setConnectionElapsedTime(long); method public final void setConnectionProperties(int); + method public final void setConnectionStartElapsedRealTime(long); method public final void setConnectionTime(long); method public final void setDialing(); method public final void setDisconnected(android.telecom.DisconnectCause); @@ -39378,12 +39380,14 @@ package android.telecom { method public final int getState(); method public final android.telecom.StatusHints getStatusHints(); method public final android.telecom.Connection.VideoProvider getVideoProvider(); + method public void handleRttUpgradeResponse(android.telecom.Connection.RttTextStream); method public final boolean isRingbackRequested(); method public void onAbort(); method public void onAnswer(int); method public void onAnswer(); method public void onCallAudioStateChanged(android.telecom.CallAudioState); method public void onCallEvent(java.lang.String, android.os.Bundle); + method public void onDeflect(android.net.Uri); method public void onDisconnect(); method public void onExtrasChanged(android.os.Bundle); method public void onHandoverComplete(); @@ -39395,8 +39399,10 @@ package android.telecom { method public void onReject(java.lang.String); method public void onSeparate(); method public void onShowIncomingCallUi(); + method public void onStartRtt(android.telecom.Connection.RttTextStream); method public void onStateChanged(int); method public void onStopDtmfTone(); + method public void onStopRtt(); method public void onUnhold(); method public static java.lang.String propertiesToString(int); method public final void putExtras(android.os.Bundle); @@ -39404,6 +39410,10 @@ package android.telecom { method public final void removeExtras(java.lang.String...); method public void requestBluetoothAudio(java.lang.String); method public void sendConnectionEvent(java.lang.String, android.os.Bundle); + method public final void sendRemoteRttRequest(); + method public final void sendRttInitiationFailure(int); + method public final void sendRttInitiationSuccess(); + method public final void sendRttSessionRemotelyTerminated(); method public final void setActive(); method public final void setAddress(android.net.Uri, int); method public final void setAudioModeIsVoip(boolean); @@ -39446,6 +39456,7 @@ package android.telecom { field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 3072; // 0xc00 field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 1024; // 0x400 field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800 + field public static final int CAPABILITY_SUPPORT_DEFLECT = 33554432; // 0x2000000 field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2 field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8 field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED"; @@ -39457,6 +39468,7 @@ package android.telecom { field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER"; field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20 field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10 + field public static final int PROPERTY_IS_RTT = 256; // 0x100 field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80 field public static final int STATE_ACTIVE = 4; // 0x4 field public static final int STATE_DIALING = 3; // 0x3 @@ -39476,6 +39488,12 @@ package android.telecom { field public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; // 0x4 } + public static final class Connection.RttTextStream { + method public java.lang.String read() throws java.io.IOException; + method public java.lang.String readImmediately() throws java.io.IOException; + method public void write(java.lang.String) throws java.io.IOException; + } + public static abstract class Connection.VideoProvider { ctor public Connection.VideoProvider(); method public void changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities); @@ -39516,7 +39534,9 @@ package android.telecom { method public android.telecom.PhoneAccountHandle getAccountHandle(); method public android.net.Uri getAddress(); method public android.os.Bundle getExtras(); + method public android.telecom.Connection.RttTextStream getRttTextStream(); method public int getVideoState(); + method public boolean isRequestingRtt(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.telecom.ConnectionRequest> CREATOR; } @@ -39703,23 +39723,23 @@ package android.telecom { public final class RemoteConference { method public void disconnect(); method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections(); - method public final int getConnectionCapabilities(); - method public final int getConnectionProperties(); - method public final java.util.List<android.telecom.RemoteConnection> getConnections(); + method public int getConnectionCapabilities(); + method public int getConnectionProperties(); + method public java.util.List<android.telecom.RemoteConnection> getConnections(); method public android.telecom.DisconnectCause getDisconnectCause(); - method public final android.os.Bundle getExtras(); - method public final int getState(); + method public android.os.Bundle getExtras(); + method public int getState(); method public void hold(); method public void merge(); method public void playDtmfTone(char); - method public final void registerCallback(android.telecom.RemoteConference.Callback); - method public final void registerCallback(android.telecom.RemoteConference.Callback, android.os.Handler); + method public void registerCallback(android.telecom.RemoteConference.Callback); + method public void registerCallback(android.telecom.RemoteConference.Callback, android.os.Handler); method public void separate(android.telecom.RemoteConnection); method public void setCallAudioState(android.telecom.CallAudioState); method public void stopDtmfTone(); method public void swap(); method public void unhold(); - method public final void unregisterCallback(android.telecom.RemoteConference.Callback); + method public void unregisterCallback(android.telecom.RemoteConference.Callback); } public static abstract class RemoteConference.Callback { @@ -39748,10 +39768,10 @@ package android.telecom { method public int getConnectionCapabilities(); method public int getConnectionProperties(); method public android.telecom.DisconnectCause getDisconnectCause(); - method public final android.os.Bundle getExtras(); + method public android.os.Bundle getExtras(); method public int getState(); method public android.telecom.StatusHints getStatusHints(); - method public final android.telecom.RemoteConnection.VideoProvider getVideoProvider(); + method public android.telecom.RemoteConnection.VideoProvider getVideoProvider(); method public int getVideoState(); method public void hold(); method public boolean isRingbackRequested(); @@ -40776,13 +40796,16 @@ package android.telephony { method public java.lang.String getNumber(); method public int getSimSlotIndex(); method public int getSubscriptionId(); + method public boolean isEmbedded(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.telephony.SubscriptionInfo> CREATOR; } public class SubscriptionManager { method public void addOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); + method public boolean canManageSubscription(android.telephony.SubscriptionInfo); method public static android.telephony.SubscriptionManager from(android.content.Context); + method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList(); method public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int); method public int getActiveSubscriptionInfoCount(); method public int getActiveSubscriptionInfoCountMax(); @@ -40833,6 +40856,7 @@ package android.telephony { method public java.lang.String getMeid(int); method public java.lang.String getMmsUAProfUrl(); method public java.lang.String getMmsUserAgent(); + method public java.lang.String getNai(); method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo(); method public java.lang.String getNetworkCountryIso(); method public java.lang.String getNetworkOperator(); @@ -41124,6 +41148,44 @@ package android.telephony.data { } +package android.telephony.euicc { + + public final class DownloadableSubscription implements android.os.Parcelable { + method public int describeContents(); + method public static android.telephony.euicc.DownloadableSubscription forActivationCode(java.lang.String); + method public java.lang.String getConfirmationCode(); + method public java.lang.String getEncodedActivationCode(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.euicc.DownloadableSubscription> CREATOR; + } + + public final class EuiccInfo implements android.os.Parcelable { + ctor public EuiccInfo(java.lang.String); + method public int describeContents(); + method public java.lang.String getOsVersion(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccInfo> CREATOR; + } + + public class EuiccManager { + method public void deleteSubscription(int, android.app.PendingIntent); + method public void downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent); + method public java.lang.String getEid(); + method public android.telephony.euicc.EuiccInfo getEuiccInfo(); + method public boolean isEnabled(); + method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException; + method public void switchToSubscription(int, android.app.PendingIntent); + field public static final java.lang.String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; + field public static final java.lang.String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE"; + field public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; // 0x2 + field public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0; // 0x0 + field public static final int EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR = 1; // 0x1 + field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE"; + field public static final java.lang.String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon"; + } + +} + package android.telephony.gsm { public class GsmCellLocation extends android.telephony.CellLocation { @@ -41138,11 +41200,11 @@ package android.telephony.gsm { } public final deprecated class SmsManager { - method public final deprecated java.util.ArrayList<java.lang.String> divideMessage(java.lang.String); - method public static final deprecated android.telephony.gsm.SmsManager getDefault(); - method public final deprecated void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent); - method public final deprecated void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>); - method public final deprecated void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent); + method public deprecated java.util.ArrayList<java.lang.String> divideMessage(java.lang.String); + method public static deprecated android.telephony.gsm.SmsManager getDefault(); + method public deprecated void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent); + method public deprecated void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>); + method public deprecated void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent); field public static final deprecated int RESULT_ERROR_GENERIC_FAILURE = 1; // 0x1 field public static final deprecated int RESULT_ERROR_NO_SERVICE = 4; // 0x4 field public static final deprecated int RESULT_ERROR_NULL_PDU = 3; // 0x3 @@ -41672,6 +41734,10 @@ package android.test { package android.test.mock { + public deprecated class MockAccountManager { + method public static android.accounts.AccountManager newMockAccountManager(android.content.Context); + } + public deprecated class MockApplication extends android.app.Application { ctor public MockApplication(); } @@ -41681,6 +41747,7 @@ package android.test.mock { ctor public MockContentProvider(android.content.Context); ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]); method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>); + method public static deprecated void attachInfoForTesting(android.content.ContentProvider, android.content.Context, android.content.pm.ProviderInfo); method public int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public java.lang.String getType(android.net.Uri); method public android.net.Uri insert(android.net.Uri, android.content.ContentValues); @@ -41961,6 +42028,10 @@ package android.test.mock { method public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics); } + public deprecated class MockService { + method public static <T extends android.app.Service> void attachForTesting(android.app.Service, android.content.Context, java.lang.String, android.app.Application); + } + } package android.test.suitebuilder { @@ -45759,76 +45830,76 @@ package android.view { public final class MotionEvent extends android.view.InputEvent implements android.os.Parcelable { method public static java.lang.String actionToString(int); - method public final void addBatch(long, float, float, float, float, int); - method public final void addBatch(long, android.view.MotionEvent.PointerCoords[], int); + method public void addBatch(long, float, float, float, float, int); + method public void addBatch(long, android.view.MotionEvent.PointerCoords[], int); method public static int axisFromString(java.lang.String); method public static java.lang.String axisToString(int); - method public final int findPointerIndex(int); - method public final int getAction(); - method public final int getActionButton(); - method public final int getActionIndex(); - method public final int getActionMasked(); - method public final float getAxisValue(int); - method public final float getAxisValue(int, int); - method public final int getButtonState(); - method public final int getDeviceId(); - method public final long getDownTime(); - method public final int getEdgeFlags(); - method public final long getEventTime(); - method public final int getFlags(); - method public final float getHistoricalAxisValue(int, int); - method public final float getHistoricalAxisValue(int, int, int); - method public final long getHistoricalEventTime(int); - method public final float getHistoricalOrientation(int); - method public final float getHistoricalOrientation(int, int); - method public final void getHistoricalPointerCoords(int, int, android.view.MotionEvent.PointerCoords); - method public final float getHistoricalPressure(int); - method public final float getHistoricalPressure(int, int); - method public final float getHistoricalSize(int); - method public final float getHistoricalSize(int, int); - method public final float getHistoricalToolMajor(int); - method public final float getHistoricalToolMajor(int, int); - method public final float getHistoricalToolMinor(int); - method public final float getHistoricalToolMinor(int, int); - method public final float getHistoricalTouchMajor(int); - method public final float getHistoricalTouchMajor(int, int); - method public final float getHistoricalTouchMinor(int); - method public final float getHistoricalTouchMinor(int, int); - method public final float getHistoricalX(int); - method public final float getHistoricalX(int, int); - method public final float getHistoricalY(int); - method public final float getHistoricalY(int, int); - method public final int getHistorySize(); - method public final int getMetaState(); - method public final float getOrientation(); - method public final float getOrientation(int); - method public final void getPointerCoords(int, android.view.MotionEvent.PointerCoords); - method public final int getPointerCount(); - method public final int getPointerId(int); - method public final void getPointerProperties(int, android.view.MotionEvent.PointerProperties); - method public final float getPressure(); - method public final float getPressure(int); - method public final float getRawX(); - method public final float getRawY(); - method public final float getSize(); - method public final float getSize(int); - method public final int getSource(); - method public final float getToolMajor(); - method public final float getToolMajor(int); - method public final float getToolMinor(); - method public final float getToolMinor(int); - method public final int getToolType(int); - method public final float getTouchMajor(); - method public final float getTouchMajor(int); - method public final float getTouchMinor(); - method public final float getTouchMinor(int); - method public final float getX(); - method public final float getX(int); - method public final float getXPrecision(); - method public final float getY(); - method public final float getY(int); - method public final float getYPrecision(); - method public final boolean isButtonPressed(int); + method public int findPointerIndex(int); + method public int getAction(); + method public int getActionButton(); + method public int getActionIndex(); + method public int getActionMasked(); + method public float getAxisValue(int); + method public float getAxisValue(int, int); + method public int getButtonState(); + method public int getDeviceId(); + method public long getDownTime(); + method public int getEdgeFlags(); + method public long getEventTime(); + method public int getFlags(); + method public float getHistoricalAxisValue(int, int); + method public float getHistoricalAxisValue(int, int, int); + method public long getHistoricalEventTime(int); + method public float getHistoricalOrientation(int); + method public float getHistoricalOrientation(int, int); + method public void getHistoricalPointerCoords(int, int, android.view.MotionEvent.PointerCoords); + method public float getHistoricalPressure(int); + method public float getHistoricalPressure(int, int); + method public float getHistoricalSize(int); + method public float getHistoricalSize(int, int); + method public float getHistoricalToolMajor(int); + method public float getHistoricalToolMajor(int, int); + method public float getHistoricalToolMinor(int); + method public float getHistoricalToolMinor(int, int); + method public float getHistoricalTouchMajor(int); + method public float getHistoricalTouchMajor(int, int); + method public float getHistoricalTouchMinor(int); + method public float getHistoricalTouchMinor(int, int); + method public float getHistoricalX(int); + method public float getHistoricalX(int, int); + method public float getHistoricalY(int); + method public float getHistoricalY(int, int); + method public int getHistorySize(); + method public int getMetaState(); + method public float getOrientation(); + method public float getOrientation(int); + method public void getPointerCoords(int, android.view.MotionEvent.PointerCoords); + method public int getPointerCount(); + method public int getPointerId(int); + method public void getPointerProperties(int, android.view.MotionEvent.PointerProperties); + method public float getPressure(); + method public float getPressure(int); + method public float getRawX(); + method public float getRawY(); + method public float getSize(); + method public float getSize(int); + method public int getSource(); + method public float getToolMajor(); + method public float getToolMajor(int); + method public float getToolMinor(); + method public float getToolMinor(int); + method public int getToolType(int); + method public float getTouchMajor(); + method public float getTouchMajor(int); + method public float getTouchMinor(); + method public float getTouchMinor(int); + method public float getX(); + method public float getX(int); + method public float getXPrecision(); + method public float getY(); + method public float getY(int); + method public float getYPrecision(); + method public boolean isButtonPressed(int); method public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent.PointerProperties[], android.view.MotionEvent.PointerCoords[], int, int, float, float, int, int, int, int); method public static deprecated android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent.PointerCoords[], int, float, float, int, int, int, int); method public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int); @@ -45836,13 +45907,13 @@ package android.view { method public static android.view.MotionEvent obtain(long, long, int, float, float, int); method public static android.view.MotionEvent obtain(android.view.MotionEvent); method public static android.view.MotionEvent obtainNoHistory(android.view.MotionEvent); - method public final void offsetLocation(float, float); - method public final void recycle(); - method public final void setAction(int); - method public final void setEdgeFlags(int); - method public final void setLocation(float, float); - method public final void setSource(int); - method public final void transform(android.graphics.Matrix); + method public void offsetLocation(float, float); + method public void recycle(); + method public void setAction(int); + method public void setEdgeFlags(int); + method public void setLocation(float, float); + method public void setSource(int); + method public void transform(android.graphics.Matrix); method public void writeToParcel(android.os.Parcel, int); field public static final int ACTION_BUTTON_PRESS = 11; // 0xb field public static final int ACTION_BUTTON_RELEASE = 12; // 0xc @@ -47540,9 +47611,9 @@ package android.view { method public void addOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener); method public void addOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener); method public void addOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener); - method public final void dispatchOnDraw(); - method public final void dispatchOnGlobalLayout(); - method public final boolean dispatchOnPreDraw(); + method public void dispatchOnDraw(); + method public void dispatchOnGlobalLayout(); + method public boolean dispatchOnPreDraw(); method public boolean isAlive(); method public deprecated void removeGlobalOnLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener); method public void removeOnDrawListener(android.view.ViewTreeObserver.OnDrawListener); @@ -49534,7 +49605,7 @@ package android.webkit { ctor public URLUtil(); method public static java.lang.String composeSearchUrl(java.lang.String, java.lang.String, java.lang.String); method public static byte[] decode(byte[]) throws java.lang.IllegalArgumentException; - method public static final java.lang.String guessFileName(java.lang.String, java.lang.String, java.lang.String); + method public static java.lang.String guessFileName(java.lang.String, java.lang.String, java.lang.String); method public static java.lang.String guessUrl(java.lang.String); method public static boolean isAboutUrl(java.lang.String); method public static boolean isAssetUrl(java.lang.String); @@ -54580,7 +54651,7 @@ package java.lang { } public static final class Character.UnicodeBlock extends java.lang.Character.Subset { - method public static final java.lang.Character.UnicodeBlock forName(java.lang.String); + method public static java.lang.Character.UnicodeBlock forName(java.lang.String); method public static java.lang.Character.UnicodeBlock of(char); method public static java.lang.Character.UnicodeBlock of(int); field public static final java.lang.Character.UnicodeBlock AEGEAN_NUMBERS; @@ -54807,7 +54878,7 @@ package java.lang { } public static final class Character.UnicodeScript extends java.lang.Enum { - method public static final java.lang.Character.UnicodeScript forName(java.lang.String); + method public static java.lang.Character.UnicodeScript forName(java.lang.String); method public static java.lang.Character.UnicodeScript of(int); method public static java.lang.Character.UnicodeScript valueOf(java.lang.String); method public static final java.lang.Character.UnicodeScript[] values(); @@ -57623,8 +57694,8 @@ package java.net { ctor public URL(java.net.URL, java.lang.String) throws java.net.MalformedURLException; ctor public URL(java.net.URL, java.lang.String, java.net.URLStreamHandler) throws java.net.MalformedURLException; method public java.lang.String getAuthority(); - method public final java.lang.Object getContent() throws java.io.IOException; - method public final java.lang.Object getContent(java.lang.Class[]) throws java.io.IOException; + method public java.lang.Object getContent() throws java.io.IOException; + method public java.lang.Object getContent(java.lang.Class[]) throws java.io.IOException; method public int getDefaultPort(); method public java.lang.String getFile(); method public java.lang.String getHost(); @@ -57637,7 +57708,7 @@ package java.net { method public synchronized int hashCode(); method public java.net.URLConnection openConnection() throws java.io.IOException; method public java.net.URLConnection openConnection(java.net.Proxy) throws java.io.IOException; - method public final java.io.InputStream openStream() throws java.io.IOException; + method public java.io.InputStream openStream() throws java.io.IOException; method public boolean sameFile(java.net.URL); method public static void setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory); method public java.lang.String toExternalForm(); @@ -62293,13 +62364,13 @@ package java.text { method public int getOffset(); method public int next(); method public int previous(); - method public static final int primaryOrder(int); + method public static int primaryOrder(int); method public void reset(); - method public static final short secondaryOrder(int); + method public static short secondaryOrder(int); method public void setOffset(int); method public void setText(java.lang.String); method public void setText(java.text.CharacterIterator); - method public static final short tertiaryOrder(int); + method public static short tertiaryOrder(int); field public static final int NULLORDER = -1; // 0xffffffff } @@ -63580,7 +63651,7 @@ package java.time.chrono { } public final class HijrahDate implements java.time.chrono.ChronoLocalDate java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster { - method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.HijrahDate> atTime(java.time.LocalTime); + method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.HijrahDate> atTime(java.time.LocalTime); method public static java.time.chrono.HijrahDate from(java.time.temporal.TemporalAccessor); method public java.time.chrono.HijrahChronology getChronology(); method public java.time.chrono.HijrahEra getEra(); @@ -63667,7 +63738,7 @@ package java.time.chrono { } public final class JapaneseDate implements java.time.chrono.ChronoLocalDate java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster { - method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.JapaneseDate> atTime(java.time.LocalTime); + method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.JapaneseDate> atTime(java.time.LocalTime); method public static java.time.chrono.JapaneseDate from(java.time.temporal.TemporalAccessor); method public java.time.chrono.JapaneseChronology getChronology(); method public java.time.chrono.JapaneseEra getEra(); @@ -63723,7 +63794,7 @@ package java.time.chrono { } public final class MinguoDate implements java.time.chrono.ChronoLocalDate java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster { - method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.MinguoDate> atTime(java.time.LocalTime); + method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.MinguoDate> atTime(java.time.LocalTime); method public static java.time.chrono.MinguoDate from(java.time.temporal.TemporalAccessor); method public java.time.chrono.MinguoChronology getChronology(); method public java.time.chrono.MinguoEra getEra(); @@ -63776,7 +63847,7 @@ package java.time.chrono { } public final class ThaiBuddhistDate implements java.time.chrono.ChronoLocalDate java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster { - method public final java.time.chrono.ChronoLocalDateTime<java.time.chrono.ThaiBuddhistDate> atTime(java.time.LocalTime); + method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.ThaiBuddhistDate> atTime(java.time.LocalTime); method public static java.time.chrono.ThaiBuddhistDate from(java.time.temporal.TemporalAccessor); method public java.time.chrono.ThaiBuddhistChronology getChronology(); method public java.time.chrono.ThaiBuddhistEra getEra(); @@ -63828,8 +63899,8 @@ package java.time.format { method public <T> T parse(java.lang.CharSequence, java.time.temporal.TemporalQuery<T>); method public java.time.temporal.TemporalAccessor parseBest(java.lang.CharSequence, java.time.temporal.TemporalQuery<?>...); method public java.time.temporal.TemporalAccessor parseUnresolved(java.lang.CharSequence, java.text.ParsePosition); - method public static final java.time.temporal.TemporalQuery<java.time.Period> parsedExcessDays(); - method public static final java.time.temporal.TemporalQuery<java.lang.Boolean> parsedLeapSecond(); + method public static java.time.temporal.TemporalQuery<java.time.Period> parsedExcessDays(); + method public static java.time.temporal.TemporalQuery<java.lang.Boolean> parsedLeapSecond(); method public java.text.Format toFormat(); method public java.text.Format toFormat(java.time.temporal.TemporalQuery<?>); method public java.time.format.DateTimeFormatter withChronology(java.time.chrono.Chronology); @@ -65278,15 +65349,15 @@ package java.util { method public java.lang.String getCountry(); method public static java.util.Locale getDefault(); method public static java.util.Locale getDefault(java.util.Locale.Category); - method public final java.lang.String getDisplayCountry(); + method public java.lang.String getDisplayCountry(); method public java.lang.String getDisplayCountry(java.util.Locale); - method public final java.lang.String getDisplayLanguage(); + method public java.lang.String getDisplayLanguage(); method public java.lang.String getDisplayLanguage(java.util.Locale); - method public final java.lang.String getDisplayName(); + method public java.lang.String getDisplayName(); method public java.lang.String getDisplayName(java.util.Locale); method public java.lang.String getDisplayScript(); method public java.lang.String getDisplayScript(java.util.Locale); - method public final java.lang.String getDisplayVariant(); + method public java.lang.String getDisplayVariant(); method public java.lang.String getDisplayVariant(java.util.Locale); method public java.lang.String getExtension(char); method public java.util.Set<java.lang.Character> getExtensionKeys(); @@ -65307,7 +65378,6 @@ package java.util { method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale); method public java.util.Locale stripExtensions(); method public java.lang.String toLanguageTag(); - method public final java.lang.String toString(); field public static final java.util.Locale CANADA; field public static final java.util.Locale CANADA_FRENCH; field public static final java.util.Locale CHINA; diff --git a/api/system-current.txt b/api/system-current.txt index 97e826462812..d2c6bd064ac9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -20,6 +20,7 @@ package android { field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET"; field public static final deprecated java.lang.String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE"; field public static final java.lang.String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH"; + field public static final java.lang.String BIND_EUICC_SERVICE = "android.permission.BIND_EUICC_SERVICE"; field public static final java.lang.String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE"; field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET"; field public static final java.lang.String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE"; @@ -29,6 +30,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_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_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT"; field public static final java.lang.String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE"; field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED"; @@ -124,6 +126,7 @@ package android { field public static final java.lang.String READ_PRINT_SERVICES = "android.permission.READ_PRINT_SERVICES"; field public static final java.lang.String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS"; field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE"; + field public static final java.lang.String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES"; field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES"; field public static final java.lang.String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL"; field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL"; @@ -171,6 +174,7 @@ package android { field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY"; field public static final java.lang.String WRITE_APN_SETTINGS = "android.permission.WRITE_APN_SETTINGS"; field public static final java.lang.String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE"; + field public static final java.lang.String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"; field public static final java.lang.String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES"; field public static final java.lang.String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE"; field public static final java.lang.String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS"; @@ -694,6 +698,7 @@ package android.content { method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); field public static final java.lang.String BACKUP_SERVICE = "backup"; field public static final java.lang.String CONTEXTHUB_SERVICE = "contexthub"; + field public static final java.lang.String EUICC_CARD_SERVICE = "euicc_card"; field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control"; field public static final java.lang.String NETWORK_SCORE_SERVICE = "network_score"; field public static final java.lang.String OEM_LOCK_SERVICE = "oem_lock"; @@ -843,6 +848,7 @@ package android.content.pm { public abstract class PackageManager { method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String); + method public android.content.pm.dex.ArtManager getArtManager(); method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int); method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int); method public abstract android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String); @@ -944,6 +950,26 @@ package android.content.pm { } +package android.content.pm.dex { + + public class ArtManager { + method public boolean isRuntimeProfilingEnabled(int); + method public void snapshotRuntimeProfile(int, java.lang.String, java.lang.String, java.util.concurrent.Executor, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback); + field public static final int PROFILE_APPS = 0; // 0x0 + field public static final int PROFILE_BOOT_IMAGE = 1; // 0x1 + field public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; // 0x1 + field public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; // 0x2 + field public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; // 0x0 + } + + public static abstract class ArtManager.SnapshotRuntimeProfileCallback { + ctor public ArtManager.SnapshotRuntimeProfileCallback(); + method public abstract void onError(int); + method public abstract void onSuccess(android.os.ParcelFileDescriptor); + } + +} + package android.content.pm.permission { public final class RuntimePermissionPresentationInfo implements android.os.Parcelable { @@ -2324,10 +2350,10 @@ package android.media.soundtrigger { package android.media.tv { public final class TvContentRatingSystemInfo implements android.os.Parcelable { - method public static final android.media.tv.TvContentRatingSystemInfo createTvContentRatingSystemInfo(int, android.content.pm.ApplicationInfo); + method public static android.media.tv.TvContentRatingSystemInfo createTvContentRatingSystemInfo(int, android.content.pm.ApplicationInfo); method public int describeContents(); - method public final android.net.Uri getXmlUri(); - method public final boolean isSystemDefined(); + method public android.net.Uri getXmlUri(); + method public boolean isSystemDefined(); method public void writeToParcel(android.os.Parcel, int); } @@ -3505,6 +3531,7 @@ package android.provider { public static final class Settings.Global extends android.provider.Settings.NameValueTable { method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String, boolean); method public static void resetToDefaults(android.content.ContentResolver, java.lang.String); + field public static final java.lang.String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus"; field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update"; field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on"; field public static final java.lang.String WEBVIEW_MULTIPROCESS = "webview_multiprocess"; @@ -3547,6 +3574,125 @@ package android.security.keystore { } +package android.service.euicc { + + public final class EuiccProfileInfo implements android.os.Parcelable { + method public int describeContents(); + method public android.service.carrier.CarrierIdentifier getCarrierIdentifier(); + method public java.lang.String getIccid(); + method public java.lang.String getNickname(); + method public int getPolicyRules(); + method public int getProfileClass(); + method public java.lang.String getProfileName(); + method public java.lang.String getServiceProviderName(); + method public int getState(); + method public java.util.List<android.telephony.UiccAccessRule> getUiccAccessRules(); + method public boolean hasPolicyRule(int); + method public boolean hasPolicyRules(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.euicc.EuiccProfileInfo> CREATOR; + field public static final int POLICY_RULE_DELETE_AFTER_DISABLING = 4; // 0x4 + field public static final int POLICY_RULE_DO_NOT_DELETE = 2; // 0x2 + field public static final int POLICY_RULE_DO_NOT_DISABLE = 1; // 0x1 + field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2 + field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1 + field public static final int PROFILE_CLASS_TESTING = 0; // 0x0 + field public static final int PROFILE_STATE_DISABLED = 0; // 0x0 + field public static final int PROFILE_STATE_ENABLED = 1; // 0x1 + } + + public static final class EuiccProfileInfo.Builder { + ctor public EuiccProfileInfo.Builder(java.lang.String); + ctor public EuiccProfileInfo.Builder(android.service.euicc.EuiccProfileInfo); + method public android.service.euicc.EuiccProfileInfo build(); + method public android.service.euicc.EuiccProfileInfo.Builder setCarrierIdentifier(android.service.carrier.CarrierIdentifier); + method public android.service.euicc.EuiccProfileInfo.Builder setIccid(java.lang.String); + method public android.service.euicc.EuiccProfileInfo.Builder setNickname(java.lang.String); + method public android.service.euicc.EuiccProfileInfo.Builder setPolicyRules(int); + method public android.service.euicc.EuiccProfileInfo.Builder setProfileClass(int); + method public android.service.euicc.EuiccProfileInfo.Builder setProfileName(java.lang.String); + method public android.service.euicc.EuiccProfileInfo.Builder setServiceProviderName(java.lang.String); + method public android.service.euicc.EuiccProfileInfo.Builder setState(int); + method public android.service.euicc.EuiccProfileInfo.Builder setUiccAccessRule(java.util.List<android.telephony.UiccAccessRule>); + } + + public static abstract class EuiccProfileInfo.PolicyRule implements java.lang.annotation.Annotation { + } + + public static abstract class EuiccProfileInfo.ProfileClass implements java.lang.annotation.Annotation { + } + + public static abstract class EuiccProfileInfo.ProfileState implements java.lang.annotation.Annotation { + } + + public abstract class EuiccService extends android.app.Service { + ctor public EuiccService(); + method public android.os.IBinder onBind(android.content.Intent); + method public abstract int onDeleteSubscription(int, java.lang.String); + method public abstract int onDownloadSubscription(int, android.telephony.euicc.DownloadableSubscription, boolean, boolean); + method public abstract int onEraseSubscriptions(int); + method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean); + method public abstract android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, android.telephony.euicc.DownloadableSubscription, boolean); + method public abstract java.lang.String onGetEid(int); + method public abstract android.telephony.euicc.EuiccInfo onGetEuiccInfo(int); + method public abstract android.service.euicc.GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int); + method public abstract int onGetOtaStatus(int); + method public abstract int onRetainSubscriptionsForFactoryReset(int); + method public abstract void onStartOtaIfNecessary(int, android.service.euicc.EuiccService.OtaStatusChangedCallback); + method public abstract int onSwitchToSubscription(int, java.lang.String, boolean); + method public abstract int onUpdateSubscriptionNickname(int, java.lang.String, java.lang.String); + field public static final java.lang.String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; + field public static final java.lang.String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; + field public static final java.lang.String ACTION_RESOLVE_CONFIRMATION_CODE = "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE"; + field public static final java.lang.String ACTION_RESOLVE_DEACTIVATE_SIM = "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM"; + field public static final java.lang.String ACTION_RESOLVE_NO_PRIVILEGES = "android.service.euicc.action.RESOLVE_NO_PRIVILEGES"; + field public static final java.lang.String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI"; + field public static final java.lang.String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService"; + field public static final java.lang.String EXTRA_RESOLUTION_CALLING_PACKAGE = "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE"; + field public static final java.lang.String EXTRA_RESOLUTION_CONFIRMATION_CODE = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE"; + field public static final java.lang.String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED"; + field public static final java.lang.String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT"; + field public static final int RESULT_FIRST_USER = 1; // 0x1 + field public static final int RESULT_MUST_DEACTIVATE_SIM = -1; // 0xffffffff + field public static final int RESULT_NEED_CONFIRMATION_CODE = -2; // 0xfffffffe + field public static final int RESULT_OK = 0; // 0x0 + } + + public static abstract class EuiccService.OtaStatusChangedCallback { + ctor public EuiccService.OtaStatusChangedCallback(); + method public abstract void onOtaStatusChanged(int); + } + + public final class GetDefaultDownloadableSubscriptionListResult implements android.os.Parcelable { + ctor public GetDefaultDownloadableSubscriptionListResult(int, android.telephony.euicc.DownloadableSubscription[]); + method public int describeContents(); + method public java.util.List<android.telephony.euicc.DownloadableSubscription> getDownloadableSubscriptions(); + method public int getResult(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.euicc.GetDefaultDownloadableSubscriptionListResult> CREATOR; + } + + public final class GetDownloadableSubscriptionMetadataResult implements android.os.Parcelable { + ctor public GetDownloadableSubscriptionMetadataResult(int, android.telephony.euicc.DownloadableSubscription); + method public int describeContents(); + method public android.telephony.euicc.DownloadableSubscription getDownloadableSubscription(); + method public int getResult(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.euicc.GetDownloadableSubscriptionMetadataResult> CREATOR; + } + + public final class GetEuiccProfileInfoListResult implements android.os.Parcelable { + ctor public GetEuiccProfileInfoListResult(int, android.service.euicc.EuiccProfileInfo[], boolean); + method public int describeContents(); + method public boolean getIsRemovable(); + method public java.util.List<android.service.euicc.EuiccProfileInfo> getProfiles(); + method public int getResult(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.euicc.GetEuiccProfileInfoListResult> CREATOR; + } + +} + package android.service.notification { public final class Adjustment implements android.os.Parcelable { @@ -3861,15 +4007,15 @@ package android.telecom { } public final deprecated class Phone { - method public final void addListener(android.telecom.Phone.Listener); - method public final boolean canAddCall(); - method public final deprecated android.telecom.AudioState getAudioState(); - method public final android.telecom.CallAudioState getCallAudioState(); - method public final java.util.List<android.telecom.Call> getCalls(); - method public final void removeListener(android.telecom.Phone.Listener); + method public void addListener(android.telecom.Phone.Listener); + method public boolean canAddCall(); + method public deprecated android.telecom.AudioState getAudioState(); + method public android.telecom.CallAudioState getCallAudioState(); + method public java.util.List<android.telecom.Call> getCalls(); + method public void removeListener(android.telecom.Phone.Listener); method public void requestBluetoothAudio(java.lang.String); - method public final void setAudioRoute(int); - method public final void setMuted(boolean); + method public void setAudioRoute(int); + method public void setMuted(boolean); } public static abstract class Phone.Listener { @@ -4065,8 +4211,14 @@ package android.telephony { field public static final int RESULT_SYSTEM_ERROR = 15; // 0xf } + public class SubscriptionInfo implements android.os.Parcelable { + method public java.util.List<android.telephony.UiccAccessRule> getAccessRules(); + } + public class SubscriptionManager { + method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList(); method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int); + method public void requestEmbeddedSubscriptionInfoListRefresh(); method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>); } @@ -4185,23 +4337,30 @@ package android.telephony { field public static final int SIM_STATE_PRESENT = 11; // 0xb } + public final class UiccAccessRule implements android.os.Parcelable { + ctor public UiccAccessRule(byte[], java.lang.String, long); + method public int describeContents(); + method public int getCarrierPrivilegeStatus(android.content.pm.PackageInfo); + method public int getCarrierPrivilegeStatus(android.content.pm.Signature, java.lang.String); + method public java.lang.String getPackageName(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.UiccAccessRule> CREATOR; + } + public class UiccSlotInfo implements android.os.Parcelable { - ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int); + ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int); method public int describeContents(); method public java.lang.String getCardId(); method public int getCardStateInfo(); method public boolean getIsActive(); method public boolean getIsEuicc(); + method public int getLogicalSlotIdx(); method public void writeToParcel(android.os.Parcel, int); field public static final int CARD_STATE_INFO_ABSENT = 1; // 0x1 field public static final int CARD_STATE_INFO_ERROR = 3; // 0x3 field public static final int CARD_STATE_INFO_PRESENT = 2; // 0x2 field public static final int CARD_STATE_INFO_RESTRICTED = 4; // 0x4 field public static final android.os.Parcelable.Creator<android.telephony.UiccSlotInfo> CREATOR; - field public final java.lang.String cardId; - field public final int cardStateInfo; - field public final boolean isActive; - field public final boolean isEuicc; } public abstract class VisualVoicemailService extends android.app.Service { @@ -4298,6 +4457,125 @@ package android.telephony.data { } +package android.telephony.euicc { + + public final class DownloadableSubscription implements android.os.Parcelable { + method public java.util.List<android.telephony.UiccAccessRule> getAccessRules(); + method public java.lang.String getCarrierName(); + } + + public static final class DownloadableSubscription.Builder { + ctor public DownloadableSubscription.Builder(); + ctor public DownloadableSubscription.Builder(android.telephony.euicc.DownloadableSubscription); + method public android.telephony.euicc.DownloadableSubscription build(); + method public android.telephony.euicc.DownloadableSubscription.Builder setAccessRules(java.util.List<android.telephony.UiccAccessRule>); + method public android.telephony.euicc.DownloadableSubscription.Builder setCarrierName(java.lang.String); + method public android.telephony.euicc.DownloadableSubscription.Builder setConfirmationCode(java.lang.String); + method public android.telephony.euicc.DownloadableSubscription.Builder setEncodedActivationCode(java.lang.String); + } + + public class EuiccCardManager { + method public void authenticateServer(java.lang.String, java.lang.String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); + method public void cancelSession(java.lang.String, byte[], int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); + method public void deleteProfile(java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); + method public void disableProfile(java.lang.String, java.lang.String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); + method public void listNotifications(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>); + method public void loadBoundProfilePackage(java.lang.String, byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); + method public void prepareDownload(java.lang.String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); + method public void removeNotificationFromList(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); + method public void requestAllProfiles(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo[]>); + method public void requestDefaultSmdpAddress(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>); + method public void requestEuiccChallenge(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); + method public void requestEuiccInfo1(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); + method public void requestEuiccInfo2(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>); + method public void requestProfile(java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>); + method public void requestRulesAuthTable(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccRulesAuthTable>); + method public void requestSmdsAddress(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>); + method public void resetMemory(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); + method public void retrieveNotification(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification>); + method public void retrieveNotificationList(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>); + method public void setDefaultSmdpAddress(java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); + method public void setNickname(java.lang.String, java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>); + method public void switchToProfile(java.lang.String, java.lang.String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>); + field public static final int CANCEL_REASON_END_USER_REJECTED = 0; // 0x0 + field public static final int CANCEL_REASON_POSTPONED = 1; // 0x1 + field public static final int CANCEL_REASON_PPR_NOT_ALLOWED = 3; // 0x3 + field public static final int CANCEL_REASON_TIMEOUT = 2; // 0x2 + field public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2; // 0x2 + field public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; // 0x1 + field public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 4; // 0x4 + field public static final int RESULT_OK = 0; // 0x0 + field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff + } + + public static abstract class EuiccCardManager.CancelReason implements java.lang.annotation.Annotation { + } + + public static abstract class EuiccCardManager.ResetOption implements java.lang.annotation.Annotation { + } + + public static abstract interface EuiccCardManager.ResultCallback<T> { + method public abstract void onComplete(int, T); + } + + public class EuiccManager { + method public void continueOperation(android.content.Intent, android.os.Bundle); + method public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent); + method public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent); + method public int getOtaStatus(); + field public static final java.lang.String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED"; + field public static final java.lang.String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; + field public static final int EUICC_OTA_FAILED = 2; // 0x2 + field public static final int EUICC_OTA_IN_PROGRESS = 1; // 0x1 + field public static final int EUICC_OTA_NOT_NEEDED = 4; // 0x4 + field public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; // 0x5 + field public static final int EUICC_OTA_SUCCEEDED = 3; // 0x3 + field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION"; + field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS"; + } + + public static abstract class EuiccManager.OtaStatus implements java.lang.annotation.Annotation { + } + + public final class EuiccNotification implements android.os.Parcelable { + ctor public EuiccNotification(int, java.lang.String, int, byte[]); + method public int describeContents(); + method public byte[] getData(); + method public int getEvent(); + method public int getSeq(); + method public java.lang.String getTargetAddr(); + method public void writeToParcel(android.os.Parcel, int); + field public static final int ALL_EVENTS = 15; // 0xf + field public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccNotification> CREATOR; + field public static final int EVENT_DELETE = 8; // 0x8 + field public static final int EVENT_DISABLE = 4; // 0x4 + field public static final int EVENT_ENABLE = 2; // 0x2 + field public static final int EVENT_INSTALL = 1; // 0x1 + } + + public static abstract class EuiccNotification.Event implements java.lang.annotation.Annotation { + } + + public final class EuiccRulesAuthTable implements android.os.Parcelable { + method public int describeContents(); + method public int findIndex(int, android.service.carrier.CarrierIdentifier); + method public boolean hasPolicyRuleFlag(int, int); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccRulesAuthTable> CREATOR; + field public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1; // 0x1 + } + + public static final class EuiccRulesAuthTable.Builder { + ctor public EuiccRulesAuthTable.Builder(int); + method public android.telephony.euicc.EuiccRulesAuthTable.Builder add(int, java.util.List<android.service.carrier.CarrierIdentifier>, int); + method public android.telephony.euicc.EuiccRulesAuthTable build(); + } + + public static abstract class EuiccRulesAuthTable.PolicyRuleFlag implements java.lang.annotation.Annotation { + } + +} + package android.telephony.ims { public final class ImsCallForwardInfo implements android.os.Parcelable { @@ -4862,6 +5140,7 @@ package android.telephony.ims.stub { ctor public ImsCallSessionImplBase(); method public void accept(int, android.telephony.ims.ImsStreamMediaProfile); method public void close(); + method public void deflect(java.lang.String); method public void extendToConference(java.lang.String[]); method public java.lang.String getCallId(); method public android.telephony.ims.ImsCallProfile getCallProfile(); diff --git a/api/test-current.txt b/api/test-current.txt index 93de1c213518..bf3d0c251a4e 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -426,32 +426,6 @@ package android.service.quicksettings { } -package android.telecom { - - public abstract class Connection extends android.telecom.Conferenceable { - method public void handleRttUpgradeResponse(android.telecom.Connection.RttTextStream); - method public void onStartRtt(android.telecom.Connection.RttTextStream); - method public void onStopRtt(); - method public final void sendRemoteRttRequest(); - method public final void sendRttInitiationFailure(int); - method public final void sendRttInitiationSuccess(); - method public final void sendRttSessionRemotelyTerminated(); - field public static final int PROPERTY_IS_RTT = 256; // 0x100 - } - - public static final class Connection.RttTextStream { - method public java.lang.String read() throws java.io.IOException; - method public java.lang.String readImmediately() throws java.io.IOException; - method public void write(java.lang.String) throws java.io.IOException; - } - - public final class ConnectionRequest implements android.os.Parcelable { - method public android.telecom.Connection.RttTextStream getRttTextStream(); - method public boolean isRequestingRtt(); - } - -} - package android.telephony { public class MbmsDownloadSession implements java.lang.AutoCloseable { @@ -745,8 +719,8 @@ package android.view { } public final class MotionEvent extends android.view.InputEvent implements android.os.Parcelable { - method public final void setActionButton(int); - method public final void setButtonState(int); + method public void setActionButton(int); + method public void setButtonState(int); } public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback { diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index ab075ee0e9f2..238cb65144a8 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -167,6 +167,8 @@ public class Am extends BaseCommand { } else if (opt.equals("--no_window_animation") || opt.equals("--no-window-animation")) { instrument.noWindowAnimation = true; + } else if (opt.equals("--no-hidden-api-checks")) { + instrument.disableHiddenApiChecks = true; } else if (opt.equals("--user")) { instrument.userId = parseUserArg(nextArgRequired()); } else if (opt.equals("--abi")) { diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java index b69ef1c2fca5..432e8903ab2b 100644 --- a/cmds/am/src/com/android/commands/am/Instrument.java +++ b/cmds/am/src/com/android/commands/am/Instrument.java @@ -52,12 +52,17 @@ public class Instrument { public boolean rawMode = false; public boolean proto = false; public boolean noWindowAnimation = false; + public boolean disableHiddenApiChecks = false; public String abi = null; public int userId = UserHandle.USER_CURRENT; public Bundle args = new Bundle(); // Required public String componentNameArg; + // Disable hidden API checks for the newly started instrumentation. + // Must be kept in sync with ActivityManagerService. + private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0; + /** * Construct the instrument command runner. */ @@ -416,7 +421,8 @@ public class Instrument { } // Start the instrumentation - if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, + int flags = disableHiddenApiChecks ? INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS : 0; + if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId, abi)) { throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString()); } diff --git a/cmds/webview_zygote/Android.mk b/cmds/webview_zygote/Android.mk deleted file mode 100644 index 955e58ed933b..000000000000 --- a/cmds/webview_zygote/Android.mk +++ /dev/null @@ -1,51 +0,0 @@ -# -# Copyright (C) 2016 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := webview_zygote - -LOCAL_SRC_FILES := webview_zygote.cpp - -LOCAL_CFLAGS := -Wall -Werror - -LOCAL_SHARED_LIBRARIES := \ - libandroid_runtime \ - libbinder \ - liblog \ - libcutils \ - libutils - -LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic -LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic - -LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain - -LOCAL_INIT_RC := webview_zygote32.rc - -# Always include the 32-bit version of webview_zygote. If the target is 64-bit, -# also include the 64-bit webview_zygote. -ifeq ($(TARGET_SUPPORTS_64_BIT_APPS),true) - LOCAL_INIT_RC += webview_zygote64.rc -endif - -LOCAL_MULTILIB := both - -LOCAL_MODULE_STEM_32 := webview_zygote32 -LOCAL_MODULE_STEM_64 := webview_zygote64 - -include $(BUILD_EXECUTABLE) diff --git a/cmds/webview_zygote/webview_zygote.cpp b/cmds/webview_zygote/webview_zygote.cpp deleted file mode 100644 index 88fee645b3ee..000000000000 --- a/cmds/webview_zygote/webview_zygote.cpp +++ /dev/null @@ -1,76 +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. - */ - - -#define LOG_TAG "WebViewZygote" - -#include <sys/prctl.h> - -#include <android_runtime/AndroidRuntime.h> -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <utils/Log.h> -#include <utils/String8.h> -#include <utils/Vector.h> - -namespace android { - -class WebViewRuntime : public AndroidRuntime { -public: - WebViewRuntime(char* argBlockStart, size_t argBlockSize) - : AndroidRuntime(argBlockStart, argBlockSize) {} - - ~WebViewRuntime() override {} - - void onStarted() override { - // Nothing to do since this is a zygote server. - } - - void onVmCreated(JNIEnv*) override { - // Nothing to do when the VM is created in the zygote. - } - - void onZygoteInit() override { - // Called after a new process is forked. - sp<ProcessState> proc = ProcessState::self(); - proc->startThreadPool(); - } - - void onExit(int code) override { - IPCThreadState::self()->stopProcess(); - AndroidRuntime::onExit(code); - } -}; - -} // namespace android - -int main(int argc, char* const argv[]) { - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { - LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno)); - return 12; - } - - size_t argBlockSize = 0; - for (int i = 0; i < argc; ++i) { - argBlockSize += strlen(argv[i]) + 1; - } - - android::WebViewRuntime runtime(argv[0], argBlockSize); - runtime.addOption("-Xzygote"); - - android::Vector<android::String8> args; - runtime.start("com.android.internal.os.WebViewZygoteInit", args, /*zygote=*/ true); -} diff --git a/cmds/webview_zygote/webview_zygote32.rc b/cmds/webview_zygote/webview_zygote32.rc deleted file mode 100644 index b7decc8eba3b..000000000000 --- a/cmds/webview_zygote/webview_zygote32.rc +++ /dev/null @@ -1,22 +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. -# - -service webview_zygote32 /system/bin/webview_zygote32 - user webview_zygote - socket webview_zygote stream 660 webview_zygote system - -on property:init.svc.zygote=stopped - stop webview_zygote32 diff --git a/cmds/webview_zygote/webview_zygote64.rc b/cmds/webview_zygote/webview_zygote64.rc deleted file mode 100644 index 2935b28cff55..000000000000 --- a/cmds/webview_zygote/webview_zygote64.rc +++ /dev/null @@ -1,22 +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. -# - -service webview_zygote64 /system/bin/webview_zygote64 - user webview_zygote - socket webview_zygote stream 660 webview_zygote system - -on property:init.svc.zygote=stopped - stop webview_zygote64 diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index da324fc1b092..025609e4deaf 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -7077,8 +7077,8 @@ public class Activity extends ContextThemeWrapper String appName = getApplicationInfo().loadLabel(getPackageManager()) .toString(); - String warning = "Detected problems with API compatiblity\n" - + "(please consult log for detail)"; + String warning = "Detected problems with API compatibility\n" + + "(visit g.co/dev/appcompat for more info)"; if (isAppDebuggable) { new AlertDialog.Builder(this) .setTitle(appName) diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 4d47d82260c2..5bc1e7657bc4 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -56,6 +56,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; +import android.content.pm.dex.ArtManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Bitmap; @@ -122,6 +123,8 @@ public class ApplicationPackageManager extends PackageManager { private UserManager mUserManager; @GuardedBy("mLock") private PackageInstaller mInstaller; + @GuardedBy("mLock") + private ArtManager mArtManager; @GuardedBy("mDelegates") private final ArrayList<MoveCallbackDelegate> mDelegates = new ArrayList<>(); @@ -2763,4 +2766,18 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowAsRuntimeException(); } } + + @Override + public ArtManager getArtManager() { + synchronized (mLock) { + if (mArtManager == null) { + try { + mArtManager = new ArtManager(mPM.getArtManager()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return mArtManager; + } + } } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 236a42c583e8..903031e3eadf 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -28,6 +28,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.dex.ArtManager; import android.content.pm.split.SplitDependencyLoader; import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; @@ -35,7 +36,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; @@ -49,13 +49,15 @@ import android.text.TextUtils; import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.Log; -import android.util.LogPrinter; import android.util.Slog; import android.util.SparseArray; import android.view.Display; import android.view.DisplayAdjustments; + import com.android.internal.util.ArrayUtils; + import dalvik.system.VMRuntime; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -729,13 +731,6 @@ public final class LoadedApk { } } - // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp). - private static File getPrimaryProfileFile(String packageName) { - File profileDir = Environment.getDataProfilesDePackageDirectory( - UserHandle.myUserId(), packageName); - return new File(profileDir, "primary.prof"); - } - private void setupJitProfileSupport() { if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) { return; @@ -763,10 +758,12 @@ public final class LoadedApk { return; } - final File profileFile = getPrimaryProfileFile(mPackageName); - - VMRuntime.registerAppInfo(profileFile.getPath(), - codePaths.toArray(new String[codePaths.size()])); + for (int i = codePaths.size() - 1; i >= 0; i--) { + String splitName = i == 0 ? null : mApplicationInfo.splitNames[i - 1]; + String profileFile = ArtManager.getCurrentProfilePath( + mPackageName, UserHandle.myUserId(), splitName); + VMRuntime.registerAppInfo(profileFile, new String[] {codePaths.get(i)}); + } // Register the app data directory with the reporter. It will // help deciding whether or not a dex file is the primary apk or a diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 121b58a2b104..d1500a860883 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3134,9 +3134,6 @@ public class DevicePolicyManager { /** * Flag for {@link #wipeData(int)}: also erase the device's eUICC data. - * - * TODO(b/35851809): make this public. - * @hide */ public static final int WIPE_EUICC = 0x0004; diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 6c8fe2e399fa..dc761521fbdc 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -2303,6 +2303,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.HID_DEVICE) { BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener); return true; + } else if (profile == BluetoothProfile.HEARING_AID) { + BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener); + return true; } else { return false; } @@ -2385,6 +2388,9 @@ public final class BluetoothAdapter { BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy; hidDevice.close(); break; + case BluetoothProfile.HEARING_AID: + BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; + hearingAid.close(); } } diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java new file mode 100644 index 000000000000..647e0d033fb7 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHearingAid.java @@ -0,0 +1,693 @@ +/* + * 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.bluetooth; + +import android.Manifest; +import android.annotation.RequiresPermission; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * This class provides the public APIs to control the Bluetooth Hearing Aid + * profile. + * + * <p>BluetoothHearingAid is a proxy object for controlling the Bluetooth Hearing Aid + * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get + * the BluetoothHearingAid proxy object. + * + * <p> Each method is protected with its appropriate permission. + * @hide + */ +public final class BluetoothHearingAid implements BluetoothProfile { + private static final String TAG = "BluetoothHearingAid"; + private static final boolean DBG = false; + private static final boolean VDBG = false; + + /** + * Intent used to broadcast the change in connection state of the Hearing Aid + * profile. + * + * <p>This intent will have 3 extras: + * <ul> + * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> + * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> + * </ul> + * + * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of + * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, + * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_CONNECTION_STATE_CHANGED = + "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED"; + + /** + * Intent used to broadcast the change in the Playing state of the Hearing Aid + * profile. + * + * <p>This intent will have 3 extras: + * <ul> + * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> + * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> + * </ul> + * + * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of + * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING}, + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_PLAYING_STATE_CHANGED = + "android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED"; + + /** + * Intent used to broadcast the selection of a connected device as active. + * + * <p>This intent will have one extra: + * <ul> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can + * be null if no device is active. </li> + * </ul> + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_ACTIVE_DEVICE_CHANGED = + "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED"; + + /** + * Hearing Aid device is streaming music. This state can be one of + * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of + * {@link #ACTION_PLAYING_STATE_CHANGED} intent. + */ + public static final int STATE_PLAYING = 10; + + /** + * Hearing Aid device is NOT streaming music. This state can be one of + * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of + * {@link #ACTION_PLAYING_STATE_CHANGED} intent. + */ + public static final int STATE_NOT_PLAYING = 11; + + /** This device represents Left Hearing Aid. */ + public static final int SIDE_LEFT = IBluetoothHearingAid.SIDE_LEFT; + + /** This device represents Right Hearing Aid. */ + public static final int SIDE_RIGHT = IBluetoothHearingAid.SIDE_RIGHT; + + /** This device is Monaural. */ + public static final int MODE_MONAURAL = IBluetoothHearingAid.MODE_MONAURAL; + + /** This device is Binaural (should receive only left or right audio). */ + public static final int MODE_BINAURAL = IBluetoothHearingAid.MODE_BINAURAL; + + /** Can't read ClientID for this device */ + public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID; + + private Context mContext; + private ServiceListener mServiceListener; + private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); + @GuardedBy("mServiceLock") + private IBluetoothHearingAid mService; + private BluetoothAdapter mAdapter; + + private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = + new IBluetoothStateChangeCallback.Stub() { + public void onBluetoothStateChange(boolean up) { + if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); + if (!up) { + if (VDBG) Log.d(TAG, "Unbinding service..."); + try { + mServiceLock.writeLock().lock(); + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG, "", re); + } finally { + mServiceLock.writeLock().unlock(); + } + } else { + try { + mServiceLock.readLock().lock(); + if (mService == null) { + if (VDBG) Log.d(TAG, "Binding service..."); + doBind(); + } + } catch (Exception re) { + Log.e(TAG, "", re); + } finally { + mServiceLock.readLock().unlock(); + } + } + } + }; + + /** + * Create a BluetoothHearingAid proxy object for interacting with the local + * Bluetooth Hearing Aid service. + */ + /*package*/ BluetoothHearingAid(Context context, ServiceListener l) { + mContext = context; + mServiceListener = l; + mAdapter = BluetoothAdapter.getDefaultAdapter(); + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + } + + doBind(); + } + + void doBind() { + Intent intent = new Intent(IBluetoothHearingAid.class.getName()); + ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); + intent.setComponent(comp); + if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, + android.os.Process.myUserHandle())) { + Log.e(TAG, "Could not bind to Bluetooth Hearing Aid Service with " + intent); + return; + } + } + + /*package*/ void close() { + mServiceListener = null; + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); + } catch (Exception e) { + Log.e(TAG, "", e); + } + } + + try { + mServiceLock.writeLock().lock(); + if (mService != null) { + mService = null; + mContext.unbindService(mConnection); + } + } catch (Exception re) { + Log.e(TAG, "", re); + } finally { + mServiceLock.writeLock().unlock(); + } + } + + @Override + public void finalize() { + // The empty finalize needs to be kept or the + // cts signature tests would fail. + } + + /** + * Initiate connection to a profile of the remote bluetooth device. + * + * <p> This API returns false in scenarios like the profile on the + * device is already connected or Bluetooth is not turned on. + * When this API returns true, it is guaranteed that + * connection state intent for the profile will be broadcasted with + * the state. Users can get the connection state of the profile + * from this intent. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission. + * + * @param device Remote Bluetooth Device + * @return false on immediate error, true otherwise + * @hide + */ + public boolean connect(BluetoothDevice device) { + if (DBG) log("connect(" + device + ")"); + try { + mServiceLock.readLock().lock(); + if (mService != null && isEnabled() && isValidDevice(device)) { + return mService.connect(device); + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * Initiate disconnection from a profile + * + * <p> This API will return false in scenarios like the profile on the + * Bluetooth device is not in connected state etc. When this API returns, + * true, it is guaranteed that the connection state change + * intent will be broadcasted with the state. Users can get the + * disconnection state of the profile from this intent. + * + * <p> If the disconnection is initiated by a remote device, the state + * will transition from {@link #STATE_CONNECTED} to + * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the + * host (local) device the state will transition from + * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to + * state {@link #STATE_DISCONNECTED}. The transition to + * {@link #STATE_DISCONNECTING} can be used to distinguish between the + * two scenarios. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission. + * + * @param device Remote Bluetooth Device + * @return false on immediate error, true otherwise + * @hide + */ + public boolean disconnect(BluetoothDevice device) { + if (DBG) log("disconnect(" + device + ")"); + try { + mServiceLock.readLock().lock(); + if (mService != null && isEnabled() && isValidDevice(device)) { + return mService.disconnect(device); + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public List<BluetoothDevice> getConnectedDevices() { + if (VDBG) log("getConnectedDevices()"); + try { + mServiceLock.readLock().lock(); + if (mService != null && isEnabled()) { + return mService.getConnectedDevices(); + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + if (VDBG) log("getDevicesMatchingStates()"); + try { + mServiceLock.readLock().lock(); + if (mService != null && isEnabled()) { + return mService.getDevicesMatchingConnectionStates(states); + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getConnectionState(BluetoothDevice device) { + if (VDBG) log("getState(" + device + ")"); + try { + mServiceLock.readLock().lock(); + if (mService != null && isEnabled() + && isValidDevice(device)) { + return mService.getConnectionState(device); + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return BluetoothProfile.STATE_DISCONNECTED; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return BluetoothProfile.STATE_DISCONNECTED; + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * Set priority of the profile + * + * <p> The device should already be paired. + * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager + * {@link #PRIORITY_OFF}, + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission. + * + * @param device Paired bluetooth device + * @param priority + * @return true if priority is set, false on error + * @hide + */ + public boolean setPriority(BluetoothDevice device, int priority) { + if (DBG) log("setPriority(" + device + ", " + priority + ")"); + try { + mServiceLock.readLock().lock(); + if (mService != null && isEnabled() + && isValidDevice(device)) { + if (priority != BluetoothProfile.PRIORITY_OFF + && priority != BluetoothProfile.PRIORITY_ON) { + return false; + } + return mService.setPriority(device, priority); + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * Get the priority of the profile. + * + * <p> The priority can be any of: + * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF}, + * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} + * + * @param device Bluetooth device + * @return priority of the device + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public int getPriority(BluetoothDevice device) { + if (VDBG) log("getPriority(" + device + ")"); + try { + mServiceLock.readLock().lock(); + if (mService != null && isEnabled() + && isValidDevice(device)) { + return mService.getPriority(device); + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return BluetoothProfile.PRIORITY_OFF; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return BluetoothProfile.PRIORITY_OFF; + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * Helper for converting a state to a string. + * + * For debug use only - strings are not internationalized. + * + * @hide + */ + public static String stateToString(int state) { + switch (state) { + case STATE_DISCONNECTED: + return "disconnected"; + case STATE_CONNECTING: + return "connecting"; + case STATE_CONNECTED: + return "connected"; + case STATE_DISCONNECTING: + return "disconnecting"; + case STATE_PLAYING: + return "playing"; + case STATE_NOT_PLAYING: + return "not playing"; + default: + return "<unknown state " + state + ">"; + } + } + + /** + * Get the volume of the device. + * + * <p> The volume is between -128 dB (mute) to 0 dB. + * + * @return volume of the hearing aid device. + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public int getVolume() { + if (VDBG) { + log("getVolume()"); + } + try { + mServiceLock.readLock().lock(); + if (mService != null && isEnabled()) { + return mService.getVolume(); + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return 0; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return 0; + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * Tells remote device to adjust volume. Uses the following values: + * <ul> + * <li>{@link AudioManager#ADJUST_LOWER}</li> + * <li>{@link AudioManager#ADJUST_RAISE}</li> + * <li>{@link AudioManager#ADJUST_MUTE}</li> + * <li>{@link AudioManager#ADJUST_UNMUTE}</li> + * </ul> + * + * @param direction One of the supported adjust values. + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public void adjustVolume(int direction) { + if (DBG) log("adjustVolume(" + direction + ")"); + + try { + mServiceLock.readLock().lock(); + + if (mService == null) { + Log.w(TAG, "Proxy not attached to service"); + return; + } + + if (!isEnabled()) return; + + mService.adjustVolume(direction); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * Tells remote device to set an absolute volume. + * + * @param volume Absolute volume to be set on remote + * @hide + */ + public void setVolume(int volume) { + if (DBG) Log.d(TAG, "setVolume(" + volume + ")"); + + try { + mServiceLock.readLock().lock(); + if (mService == null) { + Log.w(TAG, "Proxy not attached to service"); + return; + } + + if (!isEnabled()) return; + + mService.setVolume(volume); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * Get the CustomerId of the device. + * + * @param device Bluetooth device + * @return the CustomerId of the device + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public long getHiSyncId(BluetoothDevice device) { + if (VDBG) { + log("getCustomerId(" + device + ")"); + } + try { + mServiceLock.readLock().lock(); + if (mService == null) { + Log.w(TAG, "Proxy not attached to service"); + return HI_SYNC_ID_INVALID; + } + + if (!isEnabled() || !isValidDevice(device)) return HI_SYNC_ID_INVALID; + + return mService.getHiSyncId(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return HI_SYNC_ID_INVALID; + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * Get the side of the device. + * + * @param device Bluetooth device. + * @return SIDE_LEFT or SIDE_RIGHT + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public int getDeviceSide(BluetoothDevice device) { + if (VDBG) { + log("getDeviceSide(" + device + ")"); + } + try { + mServiceLock.readLock().lock(); + if (mService != null && isEnabled() + && isValidDevice(device)) { + return mService.getDeviceSide(device); + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return SIDE_LEFT; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return SIDE_LEFT; + } finally { + mServiceLock.readLock().unlock(); + } + } + + /** + * Get the mode of the device. + * + * @param device Bluetooth device + * @return MODE_MONAURAL or MODE_BINAURAL + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public int getDeviceMode(BluetoothDevice device) { + if (VDBG) { + log("getDeviceMode(" + device + ")"); + } + try { + mServiceLock.readLock().lock(); + if (mService != null && isEnabled() + && isValidDevice(device)) { + return mService.getDeviceMode(device); + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return MODE_MONAURAL; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return MODE_MONAURAL; + } finally { + mServiceLock.readLock().unlock(); + } + } + + private final ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + if (DBG) Log.d(TAG, "Proxy object connected"); + try { + mServiceLock.writeLock().lock(); + mService = IBluetoothHearingAid.Stub.asInterface(Binder.allowBlocking(service)); + } finally { + mServiceLock.writeLock().unlock(); + } + + if (mServiceListener != null) { + mServiceListener.onServiceConnected(BluetoothProfile.HEARING_AID, + BluetoothHearingAid.this); + } + } + + public void onServiceDisconnected(ComponentName className) { + if (DBG) Log.d(TAG, "Proxy object disconnected"); + try { + mServiceLock.writeLock().lock(); + mService = null; + } finally { + mServiceLock.writeLock().unlock(); + } + if (mServiceListener != null) { + mServiceListener.onServiceDisconnected(BluetoothProfile.HEARING_AID); + } + } + }; + + private boolean isEnabled() { + if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; + return false; + } + + private boolean isValidDevice(BluetoothDevice device) { + if (device == null) return false; + + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; + } + + private static void log(String msg) { + Log.d(TAG, msg); + } +} diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 0e2263f773b8..656188fbdfb8 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -165,12 +165,19 @@ public interface BluetoothProfile { public static final int OPP = 20; /** + * Hearing Aid Device + * + * @hide + */ + int HEARING_AID = 21; + + /** * Max profile ID. This value should be updated whenever a new profile is added to match * the largest value assigned to a profile. * * @hide */ - public static final int MAX_PROFILE_ID = 20; + int MAX_PROFILE_ID = 21; /** * Default priority for devices that we try to auto-connect to and diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java index 76cb3f5b548e..0a0d21498032 100644 --- a/core/java/android/bluetooth/BluetoothUuid.java +++ b/core/java/android/bluetooth/BluetoothUuid.java @@ -79,6 +79,9 @@ public final class BluetoothUuid { ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB"); public static final ParcelUuid SAP = ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB"); + /* TODO: b/69623109 update this value. It will change to 16bit UUID!! */ + public static final ParcelUuid HearingAid = + ParcelUuid.fromString("7312C48F-22CC-497F-85FD-A0616A3B9E05"); public static final ParcelUuid BASE_UUID = ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB"); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 2859326107b8..d13575822d4a 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3583,10 +3583,8 @@ public abstract class Context { * * @see #getSystemService * @see android.telephony.euicc.EuiccManager - * TODO(b/35851809): Unhide this API. - * @hide */ - public static final String EUICC_SERVICE = "euicc_service"; + public static final String EUICC_SERVICE = "euicc"; /** * Use with {@link #getSystemService(String)} to retrieve a @@ -3594,10 +3592,10 @@ public abstract class Context { * * @see #getSystemService(String) * @see android.telephony.euicc.EuiccCardManager - * TODO(b/35851809): Make this a SystemApi. * @hide */ - public static final String EUICC_CARD_SERVICE = "euicc_card_service"; + @SystemApi + public static final String EUICC_CARD_SERVICE = "euicc_card"; /** * Use with {@link #getSystemService(String)} to retrieve a diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 0e706456b9b2..73a403dd41f7 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -48,6 +48,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; +import android.content.pm.dex.IArtManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; @@ -664,4 +665,6 @@ interface IPackageManager { ComponentName getInstantAppInstallerComponent(); String getInstantAppAndroidId(String packageName, int userId); + + IArtManager getArtManager(); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 89751dadd29d..6f98adca72ac 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -42,6 +42,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.dex.ArtManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Rect; @@ -1316,6 +1317,15 @@ public abstract class PackageManager { */ public static final int INSTALL_FAILED_INSTANT_APP_INVALID = -116; + /** + * Installation parse return code: this is passed in the + * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the dex metadata file is invalid or + * if there was no matching apk file for a dex metadata file. + * + * @hide + */ + public static final int INSTALL_FAILED_BAD_DEX_METADATA = -117; + /** @hide */ @IntDef(flag = true, prefix = { "DELETE_" }, value = { DELETE_KEEP_DATA, @@ -2078,8 +2088,6 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device * supports embedded subscriptions on eUICCs. - * TODO(b/35851809): Make this public. - * @hide */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc"; @@ -5634,6 +5642,8 @@ public abstract class PackageManager { case INSTALL_FAILED_DUPLICATE_PERMISSION: return "INSTALL_FAILED_DUPLICATE_PERMISSION"; case INSTALL_FAILED_NO_MATCHING_ABIS: return "INSTALL_FAILED_NO_MATCHING_ABIS"; case INSTALL_FAILED_ABORTED: return "INSTALL_FAILED_ABORTED"; + case INSTALL_FAILED_BAD_DEX_METADATA: + return "INSTALL_FAILED_BAD_DEX_METADATA"; default: return Integer.toString(status); } } @@ -5678,6 +5688,7 @@ public abstract class PackageManager { case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return PackageInstaller.STATUS_FAILURE_INVALID; case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return PackageInstaller.STATUS_FAILURE_INVALID; case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_FAILED_BAD_DEX_METADATA: return PackageInstaller.STATUS_FAILURE_INVALID; case INSTALL_FAILED_INTERNAL_ERROR: return PackageInstaller.STATUS_FAILURE; case INSTALL_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE; case INSTALL_FAILED_DUPLICATE_PERMISSION: return PackageInstaller.STATUS_FAILURE_CONFLICT; @@ -5879,4 +5890,14 @@ public abstract class PackageManager { @SystemApi public abstract void registerDexModule(String dexModulePath, @Nullable DexModuleRegisterCallback callback); + + /** + * Returns the {@link ArtManager} associated with this package manager. + * + * @hide + */ + @SystemApi + public @NonNull ArtManager getArtManager() { + throw new UnsupportedOperationException("getArtManager not implemented in subclass"); + } } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index cb9ecf3e2bd8..a3e3354ee087 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -250,6 +250,9 @@ public class PackageParser { } /** @hide */ + public static final String APK_FILE_EXTENSION = ".apk"; + + /** @hide */ public static class NewPermissionInfo { public final String name; public final int sdkVersion; @@ -616,7 +619,7 @@ public class PackageParser { } public static boolean isApkPath(String path) { - return path.endsWith(".apk"); + return path.endsWith(APK_FILE_EXTENSION); } /** diff --git a/core/java/android/content/pm/dex/ArtManager.java b/core/java/android/content/pm/dex/ArtManager.java new file mode 100644 index 000000000000..075306366264 --- /dev/null +++ b/core/java/android/content/pm/dex/ArtManager.java @@ -0,0 +1,209 @@ +/** + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.dex; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.os.Environment; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Slog; + +import java.io.File; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; + +/** + * Class for retrieving various kinds of information related to the runtime artifacts of + * packages that are currently installed on the device. + * + * @hide + */ +@SystemApi +public class ArtManager { + private static final String TAG = "ArtManager"; + + /** The snapshot failed because the package was not found. */ + public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; + /** The snapshot failed because the package code path does not exist. */ + public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; + /** The snapshot failed because of an internal error (e.g. error during opening profiles). */ + public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; + + /** Constant used for applications profiles. */ + public static final int PROFILE_APPS = 0; + /** Constant used for the boot image profile. */ + public static final int PROFILE_BOOT_IMAGE = 1; + + /** @hide */ + @IntDef(flag = true, prefix = { "PROFILE_" }, value = { + PROFILE_APPS, + PROFILE_BOOT_IMAGE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ProfileType {} + + + private IArtManager mArtManager; + + /** + * @hide + */ + public ArtManager(@NonNull IArtManager manager) { + mArtManager = manager; + } + + /** + * Snapshots a runtime profile according to the {@code profileType} parameter. + * + * If {@code profileType} is {@link ArtManager#PROFILE_APPS} the method will snapshot + * the profile for for an apk belonging to the package {@code packageName}. + * The apk is identified by {@code codePath}. + * + * If {@code profileType} is {@code ArtManager.PROFILE_BOOT_IMAGE} the method will snapshot + * the profile for the boot image. In this case {@code codePath can be null}. The parameters + * {@code packageName} and {@code codePath} are ignored. + *u + * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. + * + * The result will be posted on the {@code executor} using the given {@code callback}. + * The profile will be available as a read-only {@link android.os.ParcelFileDescriptor}. + * + * This method will throw {@link IllegalStateException} if + * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given + * {@code profileType}. + * + * @param profileType the type of profile that should be snapshot (boot image or app) + * @param packageName the target package name or null if the target is the boot image + * @param codePath the code path for which the profile should be retrieved or null if + * the target is the boot image + * @param callback the callback which should be used for the result + * @param executor the executor which should be used to post the result + */ + @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES) + public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName, + @Nullable String codePath, @NonNull Executor executor, + @NonNull SnapshotRuntimeProfileCallback callback) { + Slog.d(TAG, "Requesting profile snapshot for " + packageName + ":" + codePath); + + SnapshotRuntimeProfileCallbackDelegate delegate = + new SnapshotRuntimeProfileCallbackDelegate(callback, executor); + try { + mArtManager.snapshotRuntimeProfile(profileType, packageName, codePath, delegate); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Returns true if runtime profiles are enabled for the given type, false otherwise. + * + * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. + * + * @param profileType can be either {@link ArtManager#PROFILE_APPS} + * or {@link ArtManager#PROFILE_BOOT_IMAGE} + */ + @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES) + public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) { + try { + return mArtManager.isRuntimeProfilingEnabled(profileType); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + return false; + } + + /** + * Callback used for retrieving runtime profiles. + */ + public abstract static class SnapshotRuntimeProfileCallback { + /** + * Called when the profile snapshot finished with success. + * + * @param profileReadFd the file descriptor that can be used to read the profile. Note that + * the file might be empty (which is valid profile). + */ + public abstract void onSuccess(ParcelFileDescriptor profileReadFd); + + /** + * Called when the profile snapshot finished with an error. + * + * @param errCode the error code {@see SNAPSHOT_FAILED_PACKAGE_NOT_FOUND, + * SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND, SNAPSHOT_FAILED_INTERNAL_ERROR}. + */ + public abstract void onError(int errCode); + } + + private static class SnapshotRuntimeProfileCallbackDelegate + extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub { + private final ArtManager.SnapshotRuntimeProfileCallback mCallback; + private final Executor mExecutor; + + private SnapshotRuntimeProfileCallbackDelegate( + ArtManager.SnapshotRuntimeProfileCallback callback, Executor executor) { + mCallback = callback; + mExecutor = executor; + } + + @Override + public void onSuccess(final ParcelFileDescriptor profileReadFd) { + mExecutor.execute(() -> mCallback.onSuccess(profileReadFd)); + } + + @Override + public void onError(int errCode) { + mExecutor.execute(() -> mCallback.onError(errCode)); + } + } + + /** + * Return the profile name for the given split. If {@code splitName} is null the + * method returns the profile name for the base apk. + * + * @hide + */ + public static String getProfileName(String splitName) { + return splitName == null ? "primary.prof" : splitName + ".split.prof"; + } + + /** + * Return the path to the current profile corresponding to given package and split. + * + * @hide + */ + public static String getCurrentProfilePath(String packageName, int userId, String splitName) { + File profileDir = Environment.getDataProfilesDePackageDirectory(userId, packageName); + return new File(profileDir, getProfileName(splitName)).getAbsolutePath(); + } + + /** + * Return the snapshot profile file for the given package and profile name. + * + * KEEP in sync with installd dexopt.cpp. + * TODO(calin): inject the snapshot profile name from PM to avoid the dependency. + * + * @hide + */ + public static File getProfileSnapshotFileForName(String packageName, String profileName) { + File profileDir = Environment.getDataRefProfilesDePackageDirectory(packageName); + return new File(profileDir, profileName + ".snapshot"); + } +} diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java new file mode 100644 index 000000000000..5d10b8826b00 --- /dev/null +++ b/core/java/android/content/pm/dex/DexMetadataHelper.java @@ -0,0 +1,230 @@ +/** + * 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.content.pm.dex; + +import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_DEX_METADATA; +import static android.content.pm.PackageParser.APK_FILE_EXTENSION; + +import android.content.pm.PackageParser; +import android.content.pm.PackageParser.PackageLite; +import android.content.pm.PackageParser.PackageParserException; +import android.util.ArrayMap; +import android.util.jar.StrictJarFile; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Helper class used to compute and validate the location of dex metadata files. + * + * @hide + */ +public class DexMetadataHelper { + private static final String DEX_METADATA_FILE_EXTENSION = ".dm"; + + private DexMetadataHelper() {} + + /** Return true if the given file is a dex metadata file. */ + public static boolean isDexMetadataFile(File file) { + return isDexMetadataPath(file.getName()); + } + + /** Return true if the given path is a dex metadata path. */ + private static boolean isDexMetadataPath(String path) { + return path.endsWith(DEX_METADATA_FILE_EXTENSION); + } + + /** + * Return the size (in bytes) of all dex metadata files associated with the given package. + */ + public static long getPackageDexMetadataSize(PackageLite pkg) { + long sizeBytes = 0; + Collection<String> dexMetadataList = DexMetadataHelper.getPackageDexMetadata(pkg).values(); + for (String dexMetadata : dexMetadataList) { + sizeBytes += new File(dexMetadata).length(); + } + return sizeBytes; + } + + /** + * Search for the dex metadata file associated with the given target file. + * If it exists, the method returns the dex metadata file; otherwise it returns null. + * + * Note that this performs a loose matching suitable to be used in the InstallerSession logic. + * i.e. the method will attempt to match the {@code dmFile} regardless of {@code targetFile} + * extension (e.g. 'foo.dm' will match 'foo' or 'foo.apk'). + */ + public static File findDexMetadataForFile(File targetFile) { + String dexMetadataPath = buildDexMetadataPathForFile(targetFile); + File dexMetadataFile = new File(dexMetadataPath); + return dexMetadataFile.exists() ? dexMetadataFile : null; + } + + /** + * Return the dex metadata files for the given package as a map + * [code path -> dex metadata path]. + * + * NOTE: involves I/O checks. + */ + public static Map<String, String> getPackageDexMetadata(PackageParser.Package pkg) { + return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths()); + } + + /** + * Return the dex metadata files for the given package as a map + * [code path -> dex metadata path]. + * + * NOTE: involves I/O checks. + */ + private static Map<String, String> getPackageDexMetadata(PackageLite pkg) { + return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths()); + } + + /** + * Look up the dex metadata files for the given code paths building the map + * [code path -> dex metadata]. + * + * For each code path (.apk) the method checks if a matching dex metadata file (.dm) exists. + * If it does it adds the pair to the returned map. + * + * Note that this method will do a loose + * matching based on the extension ('foo.dm' will match 'foo.apk' or 'foo'). + * + * This should only be used for code paths extracted from a package structure after the naming + * was enforced in the installer. + */ + private static Map<String, String> buildPackageApkToDexMetadataMap( + List<String> codePaths) { + ArrayMap<String, String> result = new ArrayMap<>(); + for (int i = codePaths.size() - 1; i >= 0; i--) { + String codePath = codePaths.get(i); + String dexMetadataPath = buildDexMetadataPathForFile(new File(codePath)); + + if (Files.exists(Paths.get(dexMetadataPath))) { + result.put(codePath, dexMetadataPath); + } + } + + return result; + } + + /** + * Return the dex metadata path associated with the given code path. + * (replaces '.apk' extension with '.dm') + * + * @throws IllegalArgumentException if the code path is not an .apk. + */ + public static String buildDexMetadataPathForApk(String codePath) { + if (!PackageParser.isApkPath(codePath)) { + throw new IllegalStateException( + "Corrupted package. Code path is not an apk " + codePath); + } + return codePath.substring(0, codePath.length() - APK_FILE_EXTENSION.length()) + + DEX_METADATA_FILE_EXTENSION; + } + + /** + * Return the dex metadata path corresponding to the given {@code targetFile} using a loose + * matching. + * i.e. the method will attempt to match the {@code dmFile} regardless of {@code targetFile} + * extension (e.g. 'foo.dm' will match 'foo' or 'foo.apk'). + */ + private static String buildDexMetadataPathForFile(File targetFile) { + return PackageParser.isApkFile(targetFile) + ? buildDexMetadataPathForApk(targetFile.getPath()) + : targetFile.getPath() + DEX_METADATA_FILE_EXTENSION; + } + + /** + * Validate the dex metadata files installed for the given package. + * + * @throws PackageParserException in case of errors. + */ + public static void validatePackageDexMetadata(PackageParser.Package pkg) + throws PackageParserException { + Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values(); + for (String dexMetadata : apkToDexMetadataList) { + validateDexMetadataFile(dexMetadata); + } + } + + /** + * Validate that the given file is a dex metadata archive. + * This is just a sanity validation that the file is a zip archive. + * + * @throws PackageParserException if the file is not a .dm file. + */ + private static void validateDexMetadataFile(String dmaPath) throws PackageParserException { + StrictJarFile jarFile = null; + try { + jarFile = new StrictJarFile(dmaPath, false, false); + } catch (IOException e) { + throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA, + "Error opening " + dmaPath, e); + } finally { + if (jarFile != null) { + try { + jarFile.close(); + } catch (IOException ignored) { + } + } + } + } + + /** + * Validates that all dex metadata paths in the given list have a matching apk. + * (for any foo.dm there should be either a 'foo' of a 'foo.apk' file). + * If that's not the case it throws {@code IllegalStateException}. + * + * This is used to perform a basic sanity check during adb install commands. + * (The installer does not support stand alone .dm files) + */ + public static void validateDexPaths(String[] paths) { + ArrayList<String> apks = new ArrayList<>(); + for (int i = 0; i < paths.length; i++) { + if (PackageParser.isApkPath(paths[i])) { + apks.add(paths[i]); + } + } + ArrayList<String> unmatchedDmFiles = new ArrayList<>(); + for (int i = 0; i < paths.length; i++) { + String dmPath = paths[i]; + if (isDexMetadataPath(dmPath)) { + boolean valid = false; + for (int j = apks.size() - 1; j >= 0; j--) { + if (dmPath.equals(buildDexMetadataPathForFile(new File(apks.get(j))))) { + valid = true; + break; + } + } + if (!valid) { + unmatchedDmFiles.add(dmPath); + } + } + } + if (!unmatchedDmFiles.isEmpty()) { + throw new IllegalStateException("Unmatched .dm files: " + unmatchedDmFiles); + } + } + +} diff --git a/core/java/android/content/pm/dex/IArtManager.aidl b/core/java/android/content/pm/dex/IArtManager.aidl new file mode 100644 index 000000000000..6abfdbab6e26 --- /dev/null +++ b/core/java/android/content/pm/dex/IArtManager.aidl @@ -0,0 +1,58 @@ +/* +** Copyright 2017, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.pm.dex; + +import android.content.pm.dex.ISnapshotRuntimeProfileCallback; + +/** + * A system service that provides access to runtime and compiler artifacts. + * + * @hide + */ +interface IArtManager { + /** + * Snapshots a runtime profile according to the {@code profileType} parameter. + * + * If {@code profileType} is {@link ArtManager#PROFILE_APPS} the method will snapshot + * the profile for for an apk belonging to the package {@code packageName}. + * The apk is identified by {@code codePath}. + * + * If {@code profileType} is {@code ArtManager.PROFILE_BOOT_IMAGE} the method will snapshot + * the profile for the boot image. In this case {@code codePath can be null}. The parameters + * {@code packageName} and {@code codePath} are ignored. + * + * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. + * + * The result will be posted on the {@code executor} using the given {@code callback}. + * The profile will be available as a read-only {@link android.os.ParcelFileDescriptor}. + * + * This method will throw {@link IllegalStateException} if + * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given + * {@code profileType}. + */ + oneway void snapshotRuntimeProfile(int profileType, in String packageName, + in String codePath, in ISnapshotRuntimeProfileCallback callback); + + /** + * Returns true if runtime profiles are enabled for the given type, false otherwise. + * The type can be can be either {@code ArtManager.PROFILE_APPS} + * or {@code ArtManager.PROFILE_BOOT_IMAGE}. + * + * @param profileType + */ + boolean isRuntimeProfilingEnabled(int profileType); +} diff --git a/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl b/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl new file mode 100644 index 000000000000..3b4838fc7824 --- /dev/null +++ b/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl @@ -0,0 +1,29 @@ +/* +** Copyright 2017, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.pm.dex; + +import android.os.ParcelFileDescriptor; + +/** + * Callback used to post the result of a profile-snapshot operation. + * + * @hide + */ +oneway interface ISnapshotRuntimeProfileCallback { + void onSuccess(in ParcelFileDescriptor profileReadFd); + void onError(int errCode); +} diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 7a20943e2a4b..1bafcaec280a 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1726,9 +1726,9 @@ public class InputMethodService extends AbstractInputMethodService { } /** - * Called when the input method window has been shown to the user, after - * previously not being visible. This is done after all of the UI setup - * for the window has occurred (creating its views etc). + * Called immediately before the input method window is shown to the user. + * You could override this to prepare for the window to be shown + * (update view structure etc). */ public void onWindowShown() { // Intentionally empty diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 11d338d05c68..3a8a254e8b7e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -112,8 +112,14 @@ public class ConnectivityManager { * <p/> * For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY * is set to {@code true} if there are no connected networks at all. + * + * @deprecated apps should use the more versatile {@link #requestNetwork}, + * {@link #registerNetworkCallback} or {@link #registerDefaultNetworkCallback} + * functions instead for faster and more detailed updates about the network + * changes they care about. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @Deprecated public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; /** @@ -1596,8 +1602,12 @@ public class ConnectivityManager { /** The hardware returned an error. */ public static final int ERROR_HARDWARE_ERROR = -31; + /** The NAT-T destination port for IPsec */ public static final int NATT_PORT = 4500; + /** The minimum interval in seconds between keepalive packet transmissions */ + public static final int MIN_INTERVAL = 10; + private final Network mNetwork; private final PacketKeepaliveCallback mCallback; private final Looper mLooper; @@ -2656,7 +2666,7 @@ public class ConnectivityManager { * A {@code NetworkCallback} is registered by calling * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)}, - * or {@link #registerDefaultNetworkCallback(NetworkCallback). A {@code NetworkCallback} is + * or {@link #registerDefaultNetworkCallback(NetworkCallback)}. A {@code NetworkCallback} is * unregistered by calling {@link #unregisterNetworkCallback(NetworkCallback)}. * A {@code NetworkCallback} should be registered at most once at any time. * A {@code NetworkCallback} that has been unregistered can be registered again. @@ -2685,6 +2695,32 @@ public class ConnectivityManager { * satisfying the request changes. * * @param network The {@link Network} of the satisfying network. + * @param networkCapabilities The {@link NetworkCapabilities} of the satisfying network. + * @param linkProperties The {@link LinkProperties} of the satisfying network. + * @hide + */ + public void onAvailable(Network network, NetworkCapabilities networkCapabilities, + LinkProperties linkProperties) { + // Internally only this method is called when a new network is available, and + // it calls the callback in the same way and order that older versions used + // to call so as not to change the behavior. + onAvailable(network); + if (!networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) { + onNetworkSuspended(network); + } + onCapabilitiesChanged(network, networkCapabilities); + onLinkPropertiesChanged(network, linkProperties); + } + + /** + * Called when the framework connects and has declared a new network ready for use. + * This callback may be called more than once if the {@link Network} that is + * satisfying the request changes. This will always immediately be followed by a + * call to {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} then by a + * call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}. + * + * @param network The {@link Network} of the satisfying network. */ public void onAvailable(Network network) {} @@ -2727,7 +2763,8 @@ public class ConnectivityManager { * changes capabilities but still satisfies the stated need. * * @param network The {@link Network} whose capabilities have changed. - * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this network. + * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this + * network. */ public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {} @@ -2743,7 +2780,7 @@ public class ConnectivityManager { /** * Called when the network the framework connected to for this request - * goes into {@link NetworkInfo.DetailedState.SUSPENDED}. + * goes into {@link NetworkInfo.State#SUSPENDED}. * This generally means that while the TCP connections are still live, * temporarily network data fails to transfer. Specifically this is used * on cellular networks to mask temporary outages when driving through @@ -2754,9 +2791,8 @@ public class ConnectivityManager { /** * Called when the network the framework connected to for this request - * returns from a {@link NetworkInfo.DetailedState.SUSPENDED} state. - * This should always be preceeded by a matching {@code onNetworkSuspended} - * call. + * returns from a {@link NetworkInfo.State#SUSPENDED} state. This should always be + * preceded by a matching {@link NetworkCallback#onNetworkSuspended} call. * @hide */ public void onNetworkResumed(Network network) {} @@ -2865,7 +2901,9 @@ public class ConnectivityManager { break; } case CALLBACK_AVAILABLE: { - callback.onAvailable(network); + NetworkCapabilities cap = getObject(message, NetworkCapabilities.class); + LinkProperties lp = getObject(message, LinkProperties.class); + callback.onAvailable(network, cap, lp); break; } case CALLBACK_LOSING: { diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 6a262e2c87ca..8599f47c6245 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -218,6 +218,25 @@ public final class IpSecConfig implements Parcelable { @VisibleForTesting public IpSecConfig() {} + /** Copy constructor */ + @VisibleForTesting + public IpSecConfig(IpSecConfig c) { + mMode = c.mMode; + mSourceAddress = c.mSourceAddress; + mDestinationAddress = c.mDestinationAddress; + mNetwork = c.mNetwork; + mSpiResourceId = c.mSpiResourceId; + mEncryption = c.mEncryption; + mAuthentication = c.mAuthentication; + mAuthenticatedEncryption = c.mAuthenticatedEncryption; + mEncapType = c.mEncapType; + mEncapSocketResourceId = c.mEncapSocketResourceId; + mEncapRemotePort = c.mEncapRemotePort; + mNattKeepaliveInterval = c.mNattKeepaliveInterval; + mMarkValue = c.mMarkValue; + mMarkMask = c.mMarkMask; + } + private IpSecConfig(Parcel in) { mMode = in.readInt(); mSourceAddress = in.readString(); diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 24a078fccc1d..b60984771a2d 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -19,6 +19,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -761,6 +762,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { @@ -780,6 +782,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction, IpSecTransform transform) throws IOException { try { diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 0829b4a3e9fe..60e96f943401 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -21,6 +21,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.Context; import android.os.Binder; @@ -83,9 +84,11 @@ public final class IpSecTransform implements AutoCloseable { @Retention(RetentionPolicy.SOURCE) public @interface EncapType {} - private IpSecTransform(Context context, IpSecConfig config) { + /** @hide */ + @VisibleForTesting + public IpSecTransform(Context context, IpSecConfig config) { mContext = context; - mConfig = config; + mConfig = new IpSecConfig(config); mResourceId = INVALID_RESOURCE_ID; } @@ -142,6 +145,18 @@ public final class IpSecTransform implements AutoCloseable { } /** + * Equals method used for testing + * + * @hide + */ + @VisibleForTesting + public static boolean equals(IpSecTransform lhs, IpSecTransform rhs) { + if (lhs == null || rhs == null) return (lhs == rhs); + return IpSecConfig.equals(lhs.getConfig(), rhs.getConfig()) + && lhs.mResourceId == rhs.mResourceId; + } + + /** * Deactivate this {@code IpSecTransform} and free allocated resources. * * <p>Deactivating a transform while it is still applied to a socket will result in errors on @@ -266,6 +281,10 @@ public final class IpSecTransform implements AutoCloseable { * @hide */ @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD + }) public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback, int intervalSeconds, @NonNull Handler handler) throws IOException { checkNotNull(userCallback); @@ -305,6 +324,10 @@ public final class IpSecTransform implements AutoCloseable { * @hide */ @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD + }) public void stopNattKeepalive() { synchronized (mKeepaliveCallback) { if (mKeepalive == null) { @@ -449,6 +472,7 @@ public final class IpSecTransform implements AutoCloseable { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public IpSecTransform buildTunnelModeTransform( @NonNull InetAddress sourceAddress, @NonNull IpSecManager.SecurityParameterIndex spi) diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java index 08d4ff5da966..7436ad08789e 100644 --- a/core/java/android/net/KeepalivePacketData.java +++ b/core/java/android/net/KeepalivePacketData.java @@ -16,8 +16,8 @@ package android.net; -import android.system.OsConstants; -import android.net.ConnectivityManager; +import static android.net.ConnectivityManager.PacketKeepalive.*; + import android.net.util.IpUtils; import android.os.Parcel; import android.os.Parcelable; @@ -25,13 +25,10 @@ import android.system.OsConstants; import android.util.Log; import java.net.Inet4Address; -import java.net.Inet6Address; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import static android.net.ConnectivityManager.PacketKeepalive.*; - /** * Represents the actual packets that are sent by the * {@link android.net.ConnectivityManager.PacketKeepalive} API. @@ -98,13 +95,6 @@ public class KeepalivePacketData implements Parcelable { InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort) throws InvalidPacketException { - // FIXME: remove this and actually support IPv6 keepalives - if (srcAddress instanceof Inet6Address && dstAddress instanceof Inet6Address) { - // Optimistically returning an IPv6 Keepalive Packet with no data, - // which currently only works on cellular - return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, new byte[0]); - } - if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) { throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); } diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 287bdc88dd3e..74d64704c8d2 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -26,6 +26,7 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.security.SecureRandom; import java.util.Arrays; import java.util.Random; @@ -329,16 +330,34 @@ public final class MacAddress implements Parcelable { /** * Returns a generated MAC address whose 24 least significant bits constituting the - * NIC part of the address are randomly selected. + * NIC part of the address are randomly selected and has Google OUI base. * * The locally assigned bit is always set to 1. The multicast bit is always set to 0. * - * @return a random locally assigned MacAddress. + * @return a random locally assigned, unicast MacAddress with Google OUI. + * + * @hide + */ + public static @NonNull MacAddress createRandomUnicastAddressWithGoogleBase() { + return createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom()); + } + + /** + * Returns a generated MAC address whose 46 bits, excluding the locally assigned bit and the + * unicast bit, are randomly selected. + * + * The locally assigned bit is always set to 1. The multicast bit is always set to 0. + * + * @return a random locally assigned, unicast MacAddress. * * @hide */ public static @NonNull MacAddress createRandomUnicastAddress() { - return createRandomUnicastAddress(BASE_GOOGLE_MAC, new Random()); + SecureRandom r = new SecureRandom(); + long addr = r.nextLong() & VALID_LONG_MASK; + addr |= LOCALLY_ASSIGNED_MASK; + addr &= ~MULTICAST_MASK; + return new MacAddress(addr); } /** @@ -355,8 +374,8 @@ public final class MacAddress implements Parcelable { */ public static @NonNull MacAddress createRandomUnicastAddress(MacAddress base, Random r) { long addr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong()); - addr = addr | LOCALLY_ASSIGNED_MASK; - addr = addr & ~MULTICAST_MASK; + addr |= LOCALLY_ASSIGNED_MASK; + addr &= ~MULTICAST_MASK; return new MacAddress(addr); } diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index e81ed9a21c4f..c94ae93a6f3b 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -21,7 +21,6 @@ import android.net.ConnectivityManager.NetworkCallback; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; -import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.BitUtils; @@ -116,6 +115,7 @@ public final class NetworkCapabilities implements Parcelable { NET_CAPABILITY_NOT_ROAMING, NET_CAPABILITY_FOREGROUND, NET_CAPABILITY_NOT_CONGESTED, + NET_CAPABILITY_NOT_SUSPENDED, }) public @interface NetCapability { } @@ -239,7 +239,6 @@ public final class NetworkCapabilities implements Parcelable { /** * Indicates that this network is available for use by apps, and not a network that is being * kept up in the background to facilitate fast network switching. - * @hide */ public static final int NET_CAPABILITY_FOREGROUND = 19; @@ -252,8 +251,20 @@ public final class NetworkCapabilities implements Parcelable { */ public static final int NET_CAPABILITY_NOT_CONGESTED = 20; + /** + * Indicates that this network is not currently suspended. + * <p> + * When a network is suspended, the network's IP addresses and any connections + * established on the network remain valid, but the network is temporarily unable + * to transfer data. This can happen, for example, if a cellular network experiences + * a temporary loss of signal, such as when driving through a tunnel, etc. + * A network with this capability is not suspended, so is expected to be able to + * transfer data. + */ + public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_CONGESTED; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_SUSPENDED; /** * Network capabilities that are expected to be mutable, i.e., can change while a particular @@ -262,12 +273,13 @@ public final class NetworkCapabilities implements Parcelable { private static final long MUTABLE_CAPABILITIES = // TRUSTED can change when user explicitly connects to an untrusted network in Settings. // http://b/18206275 - (1 << NET_CAPABILITY_TRUSTED) | - (1 << NET_CAPABILITY_VALIDATED) | - (1 << NET_CAPABILITY_CAPTIVE_PORTAL) | - (1 << NET_CAPABILITY_NOT_ROAMING) | - (1 << NET_CAPABILITY_FOREGROUND) | - (1 << NET_CAPABILITY_NOT_CONGESTED); + (1 << NET_CAPABILITY_TRUSTED) + | (1 << NET_CAPABILITY_VALIDATED) + | (1 << NET_CAPABILITY_CAPTIVE_PORTAL) + | (1 << NET_CAPABILITY_NOT_ROAMING) + | (1 << NET_CAPABILITY_FOREGROUND) + | (1 << NET_CAPABILITY_NOT_CONGESTED) + | (1 << NET_CAPABILITY_NOT_SUSPENDED); /** * Network capabilities that are not allowed in NetworkRequests. This exists because the @@ -1276,6 +1288,7 @@ public final class NetworkCapabilities implements Parcelable { case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING"; case NET_CAPABILITY_FOREGROUND: return "FOREGROUND"; case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED"; + case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED"; default: return Integer.toString(capability); } } diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS index 3a40cf4bf8a3..3cd37bf4fbdd 100644 --- a/core/java/android/net/OWNERS +++ b/core/java/android/net/OWNERS @@ -1,3 +1,5 @@ +set noparent + ek@google.com jsharkey@android.com jchalard@google.com diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index d5377c717366..1bb4adcebc82 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.Nullable; import android.content.Intent; import android.os.Environment; import android.os.Parcel; @@ -23,6 +24,8 @@ import android.os.Parcelable; import android.os.StrictMode; import android.util.Log; +import libcore.net.UriCodec; + import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -38,8 +41,6 @@ import java.util.Objects; import java.util.RandomAccess; import java.util.Set; -import libcore.net.UriCodec; - /** * Immutable URI reference. A URI reference includes a URI and a fragment, the * component of the URI following a '#'. Builds and parses URI references @@ -174,6 +175,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the scheme or null if this is a relative URI */ + @Nullable public abstract String getScheme(); /** @@ -208,6 +210,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the authority for this URI or null if not present */ + @Nullable public abstract String getAuthority(); /** @@ -219,6 +222,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the authority for this URI or null if not present */ + @Nullable public abstract String getEncodedAuthority(); /** @@ -228,6 +232,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the user info for this URI or null if not present */ + @Nullable public abstract String getUserInfo(); /** @@ -237,6 +242,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the user info for this URI or null if not present */ + @Nullable public abstract String getEncodedUserInfo(); /** @@ -246,6 +252,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the host for this URI or null if not present */ + @Nullable public abstract String getHost(); /** @@ -262,6 +269,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * @return the decoded path, or null if this is not a hierarchical URI * (like "mailto:nobody@google.com") or the URI is invalid */ + @Nullable public abstract String getPath(); /** @@ -270,6 +278,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * @return the encoded path, or null if this is not a hierarchical URI * (like "mailto:nobody@google.com") or the URI is invalid */ + @Nullable public abstract String getEncodedPath(); /** @@ -280,6 +289,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the decoded query or null if there isn't one */ + @Nullable public abstract String getQuery(); /** @@ -290,6 +300,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the encoded query or null if there isn't one */ + @Nullable public abstract String getEncodedQuery(); /** @@ -297,6 +308,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the decoded fragment or null if there isn't one */ + @Nullable public abstract String getFragment(); /** @@ -304,6 +316,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the encoded fragment or null if there isn't one */ + @Nullable public abstract String getEncodedFragment(); /** @@ -318,6 +331,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the decoded last segment or null if the path is empty */ + @Nullable public abstract String getLastPathSegment(); /** @@ -1666,6 +1680,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * @throws NullPointerException if key is null * @return the decoded value or null if no parameter is found */ + @Nullable public String getQueryParameter(String key) { if (isOpaque()) { throw new UnsupportedOperationException(NOT_HIERARCHICAL); diff --git a/core/java/android/os/ChildZygoteProcess.java b/core/java/android/os/ChildZygoteProcess.java new file mode 100644 index 000000000000..337a3e279a1a --- /dev/null +++ b/core/java/android/os/ChildZygoteProcess.java @@ -0,0 +1,44 @@ +/* + * 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.os; + +import android.net.LocalSocketAddress; + +/** + * Represents a connection to a child-zygote process. A child-zygote is spawend from another + * zygote process using {@link startChildZygote()}. + * + * {@hide} + */ +public class ChildZygoteProcess extends ZygoteProcess { + /** + * The PID of the child zygote process. + */ + private final int mPid; + + ChildZygoteProcess(LocalSocketAddress socketAddress, int pid) { + super(socketAddress, null); + mPid = pid; + } + + /** + * Returns the PID of the child-zygote process. + */ + public int getPid() { + return mPid; + } +} diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 5b0e5bbce2f7..d8eae8c2868e 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -291,7 +291,7 @@ public class Environment { } /** {@hide} */ - public static File getReferenceProfile(String packageName) { + public static File getDataRefProfilesDePackageDirectory(String packageName) { return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName); } diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java index 12a495bf2821..fb22194098b6 100644 --- a/core/java/android/os/VintfObject.java +++ b/core/java/android/os/VintfObject.java @@ -80,4 +80,11 @@ public class VintfObject { * ("28", ["libjpeg.so", "libbase.so"])] */ public static native Map<String, String[]> getVndkSnapshots(); + + /** + * @return target FCM version, a number specified in the device manifest + * indicating the FCM version that the device manifest implements. Null if + * device manifest doesn't specify this number (for legacy devices). + */ + public static native Long getTargetFrameworkCompatibilityMatrixVersion(); } diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 670f7949dd19..57418c8b9879 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.UUID; /*package*/ class ZygoteStartFailedEx extends Exception { ZygoteStartFailedEx(String s) { @@ -61,18 +62,27 @@ public class ZygoteProcess { /** * The name of the socket used to communicate with the primary zygote. */ - private final String mSocket; + private final LocalSocketAddress mSocket; /** * The name of the secondary (alternate ABI) zygote socket. */ - private final String mSecondarySocket; + private final LocalSocketAddress mSecondarySocket; public ZygoteProcess(String primarySocket, String secondarySocket) { + this(new LocalSocketAddress(primarySocket, LocalSocketAddress.Namespace.RESERVED), + new LocalSocketAddress(secondarySocket, LocalSocketAddress.Namespace.RESERVED)); + } + + public ZygoteProcess(LocalSocketAddress primarySocket, LocalSocketAddress secondarySocket) { mSocket = primarySocket; mSecondarySocket = secondarySocket; } + public LocalSocketAddress getPrimarySocketAddress() { + return mSocket; + } + /** * State for communicating with the zygote process. */ @@ -92,14 +102,13 @@ public class ZygoteProcess { this.abiList = abiList; } - public static ZygoteState connect(String socketAddress) throws IOException { + public static ZygoteState connect(LocalSocketAddress address) throws IOException { DataInputStream zygoteInputStream = null; BufferedWriter zygoteWriter = null; final LocalSocket zygoteSocket = new LocalSocket(); try { - zygoteSocket.connect(new LocalSocketAddress(socketAddress, - LocalSocketAddress.Namespace.RESERVED)); + zygoteSocket.connect(address); zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream()); @@ -115,8 +124,8 @@ public class ZygoteProcess { } String abiListString = getAbiList(zygoteWriter, zygoteInputStream); - Log.i("Zygote", "Process: zygote socket " + socketAddress + " opened, supported ABIS: " - + abiListString); + Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/" + + address.getName() + " opened, supported ABIS: " + abiListString); return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter, Arrays.asList(abiListString.split(","))); @@ -209,7 +218,8 @@ public class ZygoteProcess { try { return startViaZygote(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, - abi, instructionSet, appDataDir, invokeWith, zygoteArgs); + abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */, + zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -325,6 +335,8 @@ public class ZygoteProcess { * @param abi the ABI the process should use. * @param instructionSet null-ok the instruction set to use. * @param appDataDir null-ok the data directory of the app. + * @param startChildZygote Start a sub-zygote. This creates a new zygote process + * that has its state cloned from this zygote process. * @param extraArgs Additional arguments to supply to the zygote process. * @return An object that describes the result of the attempt to start the process. * @throws ZygoteStartFailedEx if process start failed for any reason @@ -340,6 +352,7 @@ public class ZygoteProcess { String instructionSet, String appDataDir, String invokeWith, + boolean startChildZygote, String[] extraArgs) throws ZygoteStartFailedEx { ArrayList<String> argsForZygote = new ArrayList<String>(); @@ -396,6 +409,10 @@ public class ZygoteProcess { argsForZygote.add(invokeWith); } + if (startChildZygote) { + argsForZygote.add("--start-child-zygote"); + } + argsForZygote.add(processClass); if (extraArgs != null) { @@ -410,6 +427,18 @@ public class ZygoteProcess { } /** + * Closes the connections to the zygote, if they exist. + */ + public void close() { + if (primaryZygoteState != null) { + primaryZygoteState.close(); + } + if (secondaryZygoteState != null) { + secondaryZygoteState.close(); + } + } + + /** * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block * and retry if the zygote is unresponsive. This method is a no-op if a connection is * already open. @@ -514,9 +543,19 @@ public class ZygoteProcess { * @param socketName The name of the socket to connect to. */ public static void waitForConnectionToZygote(String socketName) { + final LocalSocketAddress address = + new LocalSocketAddress(socketName, LocalSocketAddress.Namespace.RESERVED); + waitForConnectionToZygote(address); + } + + /** + * Try connecting to the Zygote over and over again until we hit a time-out. + * @param address The name of the socket to connect to. + */ + public static void waitForConnectionToZygote(LocalSocketAddress address) { for (int n = 20; n >= 0; n--) { try { - final ZygoteState zs = ZygoteState.connect(socketName); + final ZygoteState zs = ZygoteState.connect(address); zs.close(); return; } catch (IOException ioe) { @@ -529,6 +568,38 @@ public class ZygoteProcess { } catch (InterruptedException ie) { } } - Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + socketName); + Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName()); + } + + /** + * Starts a new zygote process as a child of this zygote. This is used to create + * secondary zygotes that inherit data from the zygote that this object + * communicates with. This returns a new ZygoteProcess representing a connection + * to the newly created zygote. Throws an exception if the zygote cannot be started. + */ + public ChildZygoteProcess startChildZygote(final String processClass, + final String niceName, + int uid, int gid, int[] gids, + int runtimeFlags, + String seInfo, + String abi, + String instructionSet) { + // Create an unguessable address in the global abstract namespace. + final LocalSocketAddress serverAddress = new LocalSocketAddress( + processClass + "/" + UUID.randomUUID().toString()); + + final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName()}; + + Process.ProcessStartResult result; + try { + result = startViaZygote(processClass, niceName, uid, gid, + gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo, + abi, instructionSet, null /* appDataDir */, null /* invokeWith */, + true /* startChildZygote */, extraArgs); + } catch (ZygoteStartFailedEx ex) { + throw new RuntimeException("Starting child-zygote through Zygote failed", ex); + } + + return new ChildZygoteProcess(serverAddress, result.pid); } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7ad4373e7907..f4842c6ca6c5 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3665,6 +3665,20 @@ public final class Settings { public static final Validator TTY_MODE_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3); /** + * User-selected RTT mode + * 0 = OFF + * 1 = FULL + * 2 = VCO + * 3 = HCO + * Uses the same constants as TTY (e.g. {@link android.telecom.TelecomManager#TTY_MODE_OFF}) + * @hide + */ + public static final String RTT_CALLING_MODE = "rtt_calling_mode"; + + /** @hide */ + public static final Validator RTT_CALLING_MODE_VALIDATOR = TTY_MODE_VALIDATOR; + + /** * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is * boolean (1 or 0). */ @@ -3984,6 +3998,7 @@ public final class Settings { DTMF_TONE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING, HEARING_AID, + RTT_CALLING_MODE, TTY_MODE, MASTER_MONO, SOUND_EFFECTS_ENABLED, @@ -4167,6 +4182,7 @@ public final class Settings { VALIDATORS.put(DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR); VALIDATORS.put(HEARING_AID, HEARING_AID_VALIDATOR); VALIDATORS.put(TTY_MODE, TTY_MODE_VALIDATOR); + VALIDATORS.put(RTT_CALLING_MODE, RTT_CALLING_MODE_VALIDATOR); VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, NOTIFICATION_LIGHT_PULSE_VALIDATOR); VALIDATORS.put(POINTER_LOCATION, POINTER_LOCATION_VALIDATOR); VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR); @@ -7838,9 +7854,8 @@ public final class Settings { * * @see android.service.euicc.EuiccService * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ + @SystemApi public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus"; /** @@ -10372,6 +10387,14 @@ public final class Settings { "storage_settings_clobber_threshold"; /** + * Exemptions to the hidden API blacklist. + * + * @hide + */ + public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = + "hidden_api_blacklist_exemptions"; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * diff --git a/core/java/android/service/euicc/EuiccProfileInfo.java b/core/java/android/service/euicc/EuiccProfileInfo.java index 8e752d1c6c1d..cb4f10455ec9 100644 --- a/core/java/android/service/euicc/EuiccProfileInfo.java +++ b/core/java/android/service/euicc/EuiccProfileInfo.java @@ -17,6 +17,7 @@ package android.service.euicc; import android.annotation.IntDef; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.service.carrier.CarrierIdentifier; @@ -26,15 +27,15 @@ import android.text.TextUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import java.util.List; import java.util.Objects; /** * Information about an embedded profile (subscription) on an eUICC. * * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ +@SystemApi public final class EuiccProfileInfo implements Parcelable { /** Profile policy rules (bit mask) */ @@ -44,6 +45,7 @@ public final class EuiccProfileInfo implements Parcelable { POLICY_RULE_DO_NOT_DELETE, POLICY_RULE_DELETE_AFTER_DISABLING }) + /** @hide */ public @interface PolicyRule {} /** Once this profile is enabled, it cannot be disabled. */ public static final int POLICY_RULE_DO_NOT_DISABLE = 1; @@ -60,6 +62,7 @@ public final class EuiccProfileInfo implements Parcelable { PROFILE_CLASS_OPERATIONAL, PROFILE_CLASS_UNSET }) + /** @hide */ public @interface ProfileClass {} /** Testing profiles */ public static final int PROFILE_CLASS_TESTING = 0; @@ -80,6 +83,7 @@ public final class EuiccProfileInfo implements Parcelable { PROFILE_STATE_ENABLED, PROFILE_STATE_UNSET }) + /** @hide */ public @interface ProfileState {} /** Disabled profiles */ public static final int PROFILE_STATE_DISABLED = 0; @@ -92,34 +96,34 @@ public final class EuiccProfileInfo implements Parcelable { public static final int PROFILE_STATE_UNSET = -1; /** The iccid of the subscription. */ - public final String iccid; + private final String mIccid; /** An optional nickname for the subscription. */ - public final @Nullable String nickname; + private final @Nullable String mNickname; /** The service provider name for the subscription. */ - public final String serviceProviderName; + private final String mServiceProviderName; /** The profile name for the subscription. */ - public final String profileName; + private final String mProfileName; /** Profile class for the subscription. */ - @ProfileClass public final int profileClass; + @ProfileClass private final int mProfileClass; /** The profile state of the subscription. */ - @ProfileState public final int state; + @ProfileState private final int mState; /** The operator Id of the subscription. */ - public final CarrierIdentifier carrierIdentifier; + private final CarrierIdentifier mCarrierIdentifier; /** The policy rules of the subscription. */ - @PolicyRule public final int policyRules; + @PolicyRule private final int mPolicyRules; /** * Optional access rules defining which apps can manage this subscription. If unset, only the * platform can manage it. */ - public final @Nullable UiccAccessRule[] accessRules; + private final @Nullable UiccAccessRule[] mAccessRules; public static final Creator<EuiccProfileInfo> CREATOR = new Creator<EuiccProfileInfo>() { @Override @@ -144,51 +148,51 @@ public final class EuiccProfileInfo implements Parcelable { if (!TextUtils.isDigitsOnly(iccid)) { throw new IllegalArgumentException("iccid contains invalid characters: " + iccid); } - this.iccid = iccid; - this.accessRules = accessRules; - this.nickname = nickname; - - this.serviceProviderName = null; - this.profileName = null; - this.profileClass = PROFILE_CLASS_UNSET; - this.state = PROFILE_CLASS_UNSET; - this.carrierIdentifier = null; - this.policyRules = 0; + this.mIccid = iccid; + this.mAccessRules = accessRules; + this.mNickname = nickname; + + this.mServiceProviderName = null; + this.mProfileName = null; + this.mProfileClass = PROFILE_CLASS_UNSET; + this.mState = PROFILE_STATE_UNSET; + this.mCarrierIdentifier = null; + this.mPolicyRules = 0; } private EuiccProfileInfo(Parcel in) { - iccid = in.readString(); - nickname = in.readString(); - serviceProviderName = in.readString(); - profileName = in.readString(); - profileClass = in.readInt(); - state = in.readInt(); + mIccid = in.readString(); + mNickname = in.readString(); + mServiceProviderName = in.readString(); + mProfileName = in.readString(); + mProfileClass = in.readInt(); + mState = in.readInt(); byte exist = in.readByte(); if (exist == (byte) 1) { - carrierIdentifier = CarrierIdentifier.CREATOR.createFromParcel(in); + mCarrierIdentifier = CarrierIdentifier.CREATOR.createFromParcel(in); } else { - carrierIdentifier = null; + mCarrierIdentifier = null; } - policyRules = in.readInt(); - accessRules = in.createTypedArray(UiccAccessRule.CREATOR); + mPolicyRules = in.readInt(); + mAccessRules = in.createTypedArray(UiccAccessRule.CREATOR); } @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeString(iccid); - dest.writeString(nickname); - dest.writeString(serviceProviderName); - dest.writeString(profileName); - dest.writeInt(profileClass); - dest.writeInt(state); - if (carrierIdentifier != null) { + dest.writeString(mIccid); + dest.writeString(mNickname); + dest.writeString(mServiceProviderName); + dest.writeString(mProfileName); + dest.writeInt(mProfileClass); + dest.writeInt(mState); + if (mCarrierIdentifier != null) { dest.writeByte((byte) 1); - carrierIdentifier.writeToParcel(dest, flags); + mCarrierIdentifier.writeToParcel(dest, flags); } else { dest.writeByte((byte) 0); } - dest.writeInt(policyRules); - dest.writeTypedArray(accessRules, flags); + dest.writeInt(mPolicyRules); + dest.writeTypedArray(mAccessRules, flags); } @Override @@ -198,45 +202,50 @@ public final class EuiccProfileInfo implements Parcelable { /** The builder to build a new {@link EuiccProfileInfo} instance. */ public static final class Builder { - public String iccid; - public UiccAccessRule[] accessRules; - public String nickname; - public String serviceProviderName; - public String profileName; - @ProfileClass public int profileClass; - @ProfileState public int state; - public CarrierIdentifier carrierIdentifier; - @PolicyRule public int policyRules; - - public Builder() {} + private String mIccid; + private List<UiccAccessRule> mAccessRules; + private String mNickname; + private String mServiceProviderName; + private String mProfileName; + @ProfileClass private int mProfileClass; + @ProfileState private int mState; + private CarrierIdentifier mCarrierIdentifier; + @PolicyRule private int mPolicyRules; + + public Builder(String value) { + if (!TextUtils.isDigitsOnly(value)) { + throw new IllegalArgumentException("iccid contains invalid characters: " + value); + } + mIccid = value; + } public Builder(EuiccProfileInfo baseProfile) { - iccid = baseProfile.iccid; - nickname = baseProfile.nickname; - serviceProviderName = baseProfile.serviceProviderName; - profileName = baseProfile.profileName; - profileClass = baseProfile.profileClass; - state = baseProfile.state; - carrierIdentifier = baseProfile.carrierIdentifier; - policyRules = baseProfile.policyRules; - accessRules = baseProfile.accessRules; + mIccid = baseProfile.mIccid; + mNickname = baseProfile.mNickname; + mServiceProviderName = baseProfile.mServiceProviderName; + mProfileName = baseProfile.mProfileName; + mProfileClass = baseProfile.mProfileClass; + mState = baseProfile.mState; + mCarrierIdentifier = baseProfile.mCarrierIdentifier; + mPolicyRules = baseProfile.mPolicyRules; + mAccessRules = Arrays.asList(baseProfile.mAccessRules); } /** Builds the profile instance. */ public EuiccProfileInfo build() { - if (iccid == null) { + if (mIccid == null) { throw new IllegalStateException("ICCID must be set for a profile."); } return new EuiccProfileInfo( - iccid, - nickname, - serviceProviderName, - profileName, - profileClass, - state, - carrierIdentifier, - policyRules, - accessRules); + mIccid, + mNickname, + mServiceProviderName, + mProfileName, + mProfileClass, + mState, + mCarrierIdentifier, + mPolicyRules, + mAccessRules); } /** Sets the iccId of the subscription. */ @@ -244,55 +253,55 @@ public final class EuiccProfileInfo implements Parcelable { if (!TextUtils.isDigitsOnly(value)) { throw new IllegalArgumentException("iccid contains invalid characters: " + value); } - iccid = value; + mIccid = value; return this; } /** Sets the nickname of the subscription. */ public Builder setNickname(String value) { - nickname = value; + mNickname = value; return this; } /** Sets the service provider name of the subscription. */ public Builder setServiceProviderName(String value) { - serviceProviderName = value; + mServiceProviderName = value; return this; } /** Sets the profile name of the subscription. */ public Builder setProfileName(String value) { - profileName = value; + mProfileName = value; return this; } /** Sets the profile class of the subscription. */ public Builder setProfileClass(@ProfileClass int value) { - profileClass = value; + mProfileClass = value; return this; } /** Sets the state of the subscription. */ public Builder setState(@ProfileState int value) { - state = value; + mState = value; return this; } /** Sets the carrier identifier of the subscription. */ public Builder setCarrierIdentifier(CarrierIdentifier value) { - carrierIdentifier = value; + mCarrierIdentifier = value; return this; } /** Sets the policy rules of the subscription. */ public Builder setPolicyRules(@PolicyRule int value) { - policyRules = value; + mPolicyRules = value; return this; } /** Sets the access rules of the subscription. */ - public Builder setUiccAccessRule(@Nullable UiccAccessRule[] value) { - accessRules = value; + public Builder setUiccAccessRule(@Nullable List<UiccAccessRule> value) { + mAccessRules = value; return this; } } @@ -306,75 +315,81 @@ public final class EuiccProfileInfo implements Parcelable { @ProfileState int state, CarrierIdentifier carrierIdentifier, @PolicyRule int policyRules, - @Nullable UiccAccessRule[] accessRules) { - this.iccid = iccid; - this.nickname = nickname; - this.serviceProviderName = serviceProviderName; - this.profileName = profileName; - this.profileClass = profileClass; - this.state = state; - this.carrierIdentifier = carrierIdentifier; - this.policyRules = policyRules; - this.accessRules = accessRules; + @Nullable List<UiccAccessRule> accessRules) { + this.mIccid = iccid; + this.mNickname = nickname; + this.mServiceProviderName = serviceProviderName; + this.mProfileName = profileName; + this.mProfileClass = profileClass; + this.mState = state; + this.mCarrierIdentifier = carrierIdentifier; + this.mPolicyRules = policyRules; + if (accessRules != null && accessRules.size() > 0) { + this.mAccessRules = accessRules.toArray(new UiccAccessRule[accessRules.size()]); + } else { + this.mAccessRules = null; + } } /** Gets the ICCID string. */ public String getIccid() { - return iccid; + return mIccid; } /** Gets the access rules. */ @Nullable - public UiccAccessRule[] getUiccAccessRules() { - return accessRules; + public List<UiccAccessRule> getUiccAccessRules() { + if (mAccessRules == null) return null; + return Arrays.asList(mAccessRules); } /** Gets the nickname. */ + @Nullable public String getNickname() { - return nickname; + return mNickname; } /** Gets the service provider name. */ public String getServiceProviderName() { - return serviceProviderName; + return mServiceProviderName; } /** Gets the profile name. */ public String getProfileName() { - return profileName; + return mProfileName; } /** Gets the profile class. */ @ProfileClass public int getProfileClass() { - return profileClass; + return mProfileClass; } /** Gets the state of the subscription. */ @ProfileState public int getState() { - return state; + return mState; } /** Gets the carrier identifier. */ public CarrierIdentifier getCarrierIdentifier() { - return carrierIdentifier; + return mCarrierIdentifier; } /** Gets the policy rules. */ @PolicyRule public int getPolicyRules() { - return policyRules; + return mPolicyRules; } /** Returns whether any policy rule exists. */ public boolean hasPolicyRules() { - return policyRules != 0; + return mPolicyRules != 0; } /** Checks whether a certain policy rule exists. */ public boolean hasPolicyRule(@PolicyRule int policy) { - return (policyRules & policy) != 0; + return (mPolicyRules & policy) != 0; } @Override @@ -387,50 +402,50 @@ public final class EuiccProfileInfo implements Parcelable { } EuiccProfileInfo that = (EuiccProfileInfo) obj; - return Objects.equals(iccid, that.iccid) - && Objects.equals(nickname, that.nickname) - && Objects.equals(serviceProviderName, that.serviceProviderName) - && Objects.equals(profileName, that.profileName) - && profileClass == that.profileClass - && state == that.state - && Objects.equals(carrierIdentifier, that.carrierIdentifier) - && policyRules == that.policyRules - && Arrays.equals(accessRules, that.accessRules); + return Objects.equals(mIccid, that.mIccid) + && Objects.equals(mNickname, that.mNickname) + && Objects.equals(mServiceProviderName, that.mServiceProviderName) + && Objects.equals(mProfileName, that.mProfileName) + && mProfileClass == that.mProfileClass + && mState == that.mState + && Objects.equals(mCarrierIdentifier, that.mCarrierIdentifier) + && mPolicyRules == that.mPolicyRules + && Arrays.equals(mAccessRules, that.mAccessRules); } @Override public int hashCode() { int result = 1; - result = 31 * result + Objects.hashCode(iccid); - result = 31 * result + Objects.hashCode(nickname); - result = 31 * result + Objects.hashCode(serviceProviderName); - result = 31 * result + Objects.hashCode(profileName); - result = 31 * result + profileClass; - result = 31 * result + state; - result = 31 * result + Objects.hashCode(carrierIdentifier); - result = 31 * result + policyRules; - result = 31 * result + Arrays.hashCode(accessRules); + result = 31 * result + Objects.hashCode(mIccid); + result = 31 * result + Objects.hashCode(mNickname); + result = 31 * result + Objects.hashCode(mServiceProviderName); + result = 31 * result + Objects.hashCode(mProfileName); + result = 31 * result + mProfileClass; + result = 31 * result + mState; + result = 31 * result + Objects.hashCode(mCarrierIdentifier); + result = 31 * result + mPolicyRules; + result = 31 * result + Arrays.hashCode(mAccessRules); return result; } @Override public String toString() { return "EuiccProfileInfo (nickname=" - + nickname + + mNickname + ", serviceProviderName=" - + serviceProviderName + + mServiceProviderName + ", profileName=" - + profileName + + mProfileName + ", profileClass=" - + profileClass + + mProfileClass + ", state=" - + state + + mState + ", CarrierIdentifier=" - + carrierIdentifier.toString() + + mCarrierIdentifier.toString() + ", policyRules=" - + policyRules + + mPolicyRules + ", accessRules=" - + Arrays.toString(accessRules) + + Arrays.toString(mAccessRules) + ")"; } } diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java index be8580074f73..b87faef5bb44 100644 --- a/core/java/android/service/euicc/EuiccService.java +++ b/core/java/android/service/euicc/EuiccService.java @@ -17,6 +17,7 @@ package android.service.euicc; import android.annotation.CallSuper; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; import android.os.IBinder; @@ -41,8 +42,11 @@ import java.util.concurrent.atomic.AtomicInteger; * <p>To implement the LPA backend, you must extend this class and declare this service in your * manifest file. The service must require the * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission and include an intent filter - * with the {@link #EUICC_SERVICE_INTERFACE} action. The priority of the intent filter must be set - * to a non-zero value in case multiple implementations are present on the device. For example: + * with the {@link #EUICC_SERVICE_INTERFACE} action. It's suggested that the priority of the intent + * filter to be set to a non-zero value in case multiple implementations are present on the device. + * See the below example. Note that there will be problem if two LPAs are present and they have the + * same priority. + * Example: * * <pre>{@code * <service android:name=".MyEuiccService" @@ -65,9 +69,9 @@ import java.util.concurrent.atomic.AtomicInteger; * filter with the appropriate action, the {@link #CATEGORY_EUICC_UI} category, and a non-zero * priority. * - * TODO(b/35851809): Make this a SystemApi. * @hide */ +@SystemApi public abstract class EuiccService extends Service { /** Action which must be included in this service's intent filter. */ public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService"; @@ -77,7 +81,10 @@ public abstract class EuiccService extends Service { // LUI actions. These are passthroughs of the corresponding EuiccManager actions. - /** @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS */ + /** + * @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS + * The difference is this one is used by system to bring up the LUI. + */ public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; /** @see android.telephony.euicc.EuiccManager#ACTION_PROVISION_EMBEDDED_SUBSCRIPTION */ @@ -88,7 +95,10 @@ public abstract class EuiccService extends Service { // require user interaction. // TODO(b/33075886): Define extras for any input parameters to these dialogs once they are // more scoped out. - /** Alert the user that this action will result in an active SIM being deactivated. */ + /** + * Alert the user that this action will result in an active SIM being deactivated. + * To implement the LUI triggered by the system, you need to define this in AndroidManifest.xml. + */ public static final String ACTION_RESOLVE_DEACTIVATE_SIM = "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM"; /** @@ -102,7 +112,11 @@ public abstract class EuiccService extends Service { public static final String ACTION_RESOLVE_CONFIRMATION_CODE = "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE"; - /** Intent extra set for resolution requests containing the package name of the calling app. */ + /** + * Intent extra set for resolution requests containing the package name of the calling app. + * This is used by the above actions including ACTION_RESOLVE_DEACTIVATE_SIM, + * ACTION_RESOLVE_NO_PRIVILEGES and ACTION_RESOLVE_CONFIRMATION_CODE. + */ public static final String EXTRA_RESOLUTION_CALLING_PACKAGE = "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE"; @@ -136,10 +150,18 @@ public abstract class EuiccService extends Service { RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE); } - /** Boolean extra for resolution actions indicating whether the user granted consent. */ - public static final String RESOLUTION_EXTRA_CONSENT = "consent"; - /** String extra for resolution actions indicating the carrier confirmation code. */ - public static final String RESOLUTION_EXTRA_CONFIRMATION_CODE = "confirmation_code"; + /** + * Boolean extra for resolution actions indicating whether the user granted consent. + * This is used and set by the implementation and used in {@code EuiccOperation}. + */ + public static final String EXTRA_RESOLUTION_CONSENT = + "android.service.euicc.extra.RESOLUTION_CONSENT"; + /** + * String extra for resolution actions indicating the carrier confirmation code. + * This is used and set by the implementation and used in {@code EuiccOperation}. + */ + public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE = + "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE"; private final IEuiccService.Stub mStubWrapper; @@ -199,9 +221,9 @@ public abstract class EuiccService extends Service { * * @see IEuiccService#startOtaIfNecessary */ - public interface OtaStatusChangedCallback { + public abstract static class OtaStatusChangedCallback { /** Called when OTA status is changed. */ - void onOtaStatusChanged(int status); + public abstract void onOtaStatusChanged(int status); } /** @@ -238,8 +260,7 @@ public abstract class EuiccService extends Service { /** * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @param subscription A subscription whose metadata needs to be populated. * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} @@ -267,8 +288,7 @@ public abstract class EuiccService extends Service { /** * Download the given subscription. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @param subscription The subscription to download. * @param switchAfterDownload If true, the subscription should be enabled upon successful * download. @@ -286,8 +306,7 @@ public abstract class EuiccService extends Service { /** * Return a list of all @link EuiccProfileInfo}s. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @return The result of the operation. * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList @@ -297,8 +316,7 @@ public abstract class EuiccService extends Service { /** * Return info about the eUICC chip/device. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @return the {@link EuiccInfo} for the eUICC chip/device. * @see android.telephony.euicc.EuiccManager#getEuiccInfo */ @@ -310,8 +328,7 @@ public abstract class EuiccService extends Service { * <p>If the subscription is currently active, it should be deactivated first (equivalent to a * physical SIM being ejected). * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @param iccid the ICCID of the subscription to delete. * @return the result of the delete operation. May be one of the predefined {@code RESULT_} * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. @@ -322,8 +339,7 @@ public abstract class EuiccService extends Service { /** * Switch to the given subscription. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @param iccid the ICCID of the subscription to enable. May be null, in which case the current * profile should be deactivated and no profile should be activated to replace it - this is * equivalent to a physical SIM being ejected. @@ -340,8 +356,7 @@ public abstract class EuiccService extends Service { /** * Update the nickname of the given subscription. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @param iccid the ICCID of the subscription to update. * @param nickname the new nickname to apply. * @return the result of the update operation. May be one of the predefined {@code RESULT_} diff --git a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java index 5a24492007f3..e2171ae6bc76 100644 --- a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java +++ b/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java @@ -16,16 +16,19 @@ package android.service.euicc; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.telephony.euicc.DownloadableSubscription; +import java.util.Arrays; +import java.util.List; + /** * Result of a {@link EuiccService#onGetDefaultDownloadableSubscriptionList} operation. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ +@SystemApi public final class GetDefaultDownloadableSubscriptionListResult implements Parcelable { public static final Creator<GetDefaultDownloadableSubscriptionListResult> CREATOR = @@ -42,20 +45,35 @@ public final class GetDefaultDownloadableSubscriptionListResult implements Parce }; /** - * Result of the operation. + * @hide + * @deprecated - Do no use. Use getResult() instead. + */ + @Deprecated + public final int result; + + @Nullable + private final DownloadableSubscription[] mSubscriptions; + + /** + * Gets the result of the operation. * * <p>May be one of the predefined {@code RESULT_} constants in EuiccService or any * implementation-specific code starting with {@link EuiccService#RESULT_FIRST_USER}. */ - public final int result; + public int getResult() { + return result; + } /** - * The available {@link DownloadableSubscription}s (with filled-in metadata). + * Gets the available {@link DownloadableSubscription}s (with filled-in metadata). * * <p>Only non-null if {@link #result} is {@link EuiccService#RESULT_OK}. */ @Nullable - public final DownloadableSubscription[] subscriptions; + public List<DownloadableSubscription> getDownloadableSubscriptions() { + if (mSubscriptions == null) return null; + return Arrays.asList(mSubscriptions); + } /** * Construct a new {@link GetDefaultDownloadableSubscriptionListResult}. @@ -70,25 +88,25 @@ public final class GetDefaultDownloadableSubscriptionListResult implements Parce @Nullable DownloadableSubscription[] subscriptions) { this.result = result; if (this.result == EuiccService.RESULT_OK) { - this.subscriptions = subscriptions; + this.mSubscriptions = subscriptions; } else { if (subscriptions != null) { throw new IllegalArgumentException( "Error result with non-null subscriptions: " + result); } - this.subscriptions = null; + this.mSubscriptions = null; } } private GetDefaultDownloadableSubscriptionListResult(Parcel in) { this.result = in.readInt(); - this.subscriptions = in.createTypedArray(DownloadableSubscription.CREATOR); + this.mSubscriptions = in.createTypedArray(DownloadableSubscription.CREATOR); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(result); - dest.writeTypedArray(subscriptions, flags); + dest.writeTypedArray(mSubscriptions, flags); } @Override diff --git a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java index de8a30706945..1edb5398add4 100644 --- a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java +++ b/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java @@ -16,6 +16,7 @@ package android.service.euicc; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.telephony.euicc.DownloadableSubscription; @@ -23,9 +24,8 @@ import android.telephony.euicc.DownloadableSubscription; /** * Result of a {@link EuiccService#onGetDownloadableSubscriptionMetadata} operation. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ +@SystemApi public final class GetDownloadableSubscriptionMetadataResult implements Parcelable { public static final Creator<GetDownloadableSubscriptionMetadataResult> CREATOR = @@ -42,20 +42,34 @@ public final class GetDownloadableSubscriptionMetadataResult implements Parcelab }; /** - * Result of the operation. + * @hide + * @deprecated - Do no use. Use getResult() instead. + */ + @Deprecated + public final int result; + + @Nullable + private final DownloadableSubscription mSubscription; + + /** + * Gets the result of the operation. * * <p>May be one of the predefined {@code RESULT_} constants in EuiccService or any * implementation-specific code starting with {@link EuiccService#RESULT_FIRST_USER}. */ - public final int result; + public int getResult() { + return result; + } /** - * The {@link DownloadableSubscription} with filled-in metadata. + * Gets the {@link DownloadableSubscription} with filled-in metadata. * * <p>Only non-null if {@link #result} is {@link EuiccService#RESULT_OK}. */ @Nullable - public final DownloadableSubscription subscription; + public DownloadableSubscription getDownloadableSubscription() { + return mSubscription; + } /** * Construct a new {@link GetDownloadableSubscriptionMetadataResult}. @@ -70,25 +84,25 @@ public final class GetDownloadableSubscriptionMetadataResult implements Parcelab @Nullable DownloadableSubscription subscription) { this.result = result; if (this.result == EuiccService.RESULT_OK) { - this.subscription = subscription; + this.mSubscription = subscription; } else { if (subscription != null) { throw new IllegalArgumentException( "Error result with non-null subscription: " + result); } - this.subscription = null; + this.mSubscription = null; } } private GetDownloadableSubscriptionMetadataResult(Parcel in) { this.result = in.readInt(); - this.subscription = in.readTypedObject(DownloadableSubscription.CREATOR); + this.mSubscription = in.readTypedObject(DownloadableSubscription.CREATOR); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(result); - dest.writeTypedObject(this.subscription, flags); + dest.writeTypedObject(this.mSubscription, flags); } @Override diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java index 7ad84888dc82..464d136e70e5 100644 --- a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java +++ b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java @@ -16,15 +16,18 @@ package android.service.euicc; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import java.util.Arrays; +import java.util.List; + /** * Result of a {@link EuiccService#onGetEuiccProfileInfoList} operation. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ +@SystemApi public final class GetEuiccProfileInfoListResult implements Parcelable { public static final Creator<GetEuiccProfileInfoListResult> CREATOR = @@ -41,19 +44,38 @@ public final class GetEuiccProfileInfoListResult implements Parcelable { }; /** - * Result of the operation. + * @hide + * @deprecated - Do no use. Use getResult() instead. + */ + @Deprecated + public final int result; + + @Nullable + private final EuiccProfileInfo[] mProfiles; + + private final boolean mIsRemovable; + + /** + * Gets the result of the operation. * * <p>May be one of the predefined {@code RESULT_} constants in EuiccService or any * implementation-specific code starting with {@link EuiccService#RESULT_FIRST_USER}. */ - public final int result; + public int getResult() { + return result; + } - /** The profile list (only upon success). */ + /** Gets the profile list (only upon success). */ @Nullable - public final EuiccProfileInfo[] profiles; + public List<EuiccProfileInfo> getProfiles() { + if (mProfiles == null) return null; + return Arrays.asList(mProfiles); + } - /** Whether the eUICC is removable. */ - public final boolean isRemovable; + /** Gets whether the eUICC is removable. */ + public boolean getIsRemovable() { + return mIsRemovable; + } /** * Construct a new {@link GetEuiccProfileInfoListResult}. @@ -71,30 +93,29 @@ public final class GetEuiccProfileInfoListResult implements Parcelable { public GetEuiccProfileInfoListResult( int result, @Nullable EuiccProfileInfo[] profiles, boolean isRemovable) { this.result = result; - this.isRemovable = isRemovable; + this.mIsRemovable = isRemovable; if (this.result == EuiccService.RESULT_OK) { - this.profiles = profiles; + this.mProfiles = profiles; } else { if (profiles != null) { throw new IllegalArgumentException( "Error result with non-null profiles: " + result); } - this.profiles = null; + this.mProfiles = null; } - } private GetEuiccProfileInfoListResult(Parcel in) { this.result = in.readInt(); - this.profiles = in.createTypedArray(EuiccProfileInfo.CREATOR); - this.isRemovable = in.readBoolean(); + this.mProfiles = in.createTypedArray(EuiccProfileInfo.CREATOR); + this.mIsRemovable = in.readBoolean(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(result); - dest.writeTypedArray(profiles, flags); - dest.writeBoolean(isRemovable); + dest.writeTypedArray(mProfiles, flags); + dest.writeBoolean(mIsRemovable); } @Override diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 668cfba94071..d06a20ba3e98 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -463,7 +463,7 @@ public final class WebViewFactory { */ public static int onWebViewProviderChanged(PackageInfo packageInfo) { String[] nativeLibs = null; - String originalSourceDir = packageInfo.applicationInfo.sourceDir; + ApplicationInfo originalAppInfo = new ApplicationInfo(packageInfo.applicationInfo); try { fixupStubApplicationInfo(packageInfo.applicationInfo, AppGlobals.getInitialApplication().getPackageManager()); @@ -474,7 +474,7 @@ public final class WebViewFactory { Log.e(LOGTAG, "error preparing webview native library", t); } - WebViewZygote.onWebViewProviderChanged(packageInfo, originalSourceDir); + WebViewZygote.onWebViewProviderChanged(packageInfo, originalAppInfo); return prepareWebViewInSystemServer(nativeLibs); } diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java index 0204dff9bf9d..d2923c4b8d12 100644 --- a/core/java/android/webkit/WebViewZygote.java +++ b/core/java/android/webkit/WebViewZygote.java @@ -17,31 +17,25 @@ package android.webkit; import android.app.LoadedApk; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.os.Build; -import android.os.SystemService; +import android.os.ChildZygoteProcess; +import android.os.Process; import android.os.ZygoteProcess; import android.text.TextUtils; -import android.util.AndroidRuntimeException; import android.util.Log; import com.android.internal.annotations.GuardedBy; import java.io.File; -import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.concurrent.TimeoutException; /** @hide */ public class WebViewZygote { private static final String LOGTAG = "WebViewZygote"; - private static final String WEBVIEW_ZYGOTE_SERVICE_32 = "webview_zygote32"; - private static final String WEBVIEW_ZYGOTE_SERVICE_64 = "webview_zygote64"; - private static final String WEBVIEW_ZYGOTE_SOCKET = "webview_zygote"; - /** * Lock object that protects all other static members. */ @@ -52,14 +46,7 @@ public class WebViewZygote { * is not running or is not connected. */ @GuardedBy("sLock") - private static ZygoteProcess sZygote; - - /** - * Variable that allows us to determine whether the WebView zygote Service has already been - * started. - */ - @GuardedBy("sLock") - private static boolean sStartedService = false; + private static ChildZygoteProcess sZygote; /** * Information about the selected WebView package. This is set from #onWebViewProviderChanged(). @@ -68,11 +55,11 @@ public class WebViewZygote { private static PackageInfo sPackage; /** - * Cache key for the selected WebView package's classloader. This is set from + * Original ApplicationInfo for the selected WebView package before stub fixup. This is set from * #onWebViewProviderChanged(). */ @GuardedBy("sLock") - private static String sPackageCacheKey; + private static ApplicationInfo sPackageOriginalAppInfo; /** * Flag for whether multi-process WebView is enabled. If this is false, the zygote @@ -85,7 +72,7 @@ public class WebViewZygote { synchronized (sLock) { if (sZygote != null) return sZygote; - waitForServiceStartAndConnect(); + connectToZygoteIfNeededLocked(); return sZygote; } } @@ -107,82 +94,43 @@ public class WebViewZygote { sMultiprocessEnabled = enabled; // When toggling between multi-process being on/off, start or stop the - // service. If it is enabled and the zygote is not yet started, bring up the service. - // Otherwise, bring down the service. The name may be null if the package - // information has not yet been resolved. - final String serviceName = getServiceNameLocked(); - if (serviceName == null) return; - + // 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) { - if (!sStartedService) { - SystemService.start(serviceName); - sStartedService = true; - } + connectToZygoteIfNeededLocked(); } else { - SystemService.stop(serviceName); - sStartedService = false; - sZygote = null; + stopZygoteLocked(); } } } - public static void onWebViewProviderChanged(PackageInfo packageInfo, String cacheKey) { + public static void onWebViewProviderChanged(PackageInfo packageInfo, + ApplicationInfo originalAppInfo) { synchronized (sLock) { sPackage = packageInfo; - sPackageCacheKey = cacheKey; + sPackageOriginalAppInfo = originalAppInfo; // If multi-process is not enabled, then do not start the zygote service. if (!sMultiprocessEnabled) { return; } - final String serviceName = getServiceNameLocked(); - sZygote = null; - - // The service may enter the RUNNING state before it opens the socket, - // so connectToZygoteIfNeededLocked() may still fail. - if (SystemService.isStopped(serviceName)) { - SystemService.start(serviceName); - } else { - SystemService.restart(serviceName); - } - sStartedService = true; - } - } - - private static void waitForServiceStartAndConnect() { - if (!sStartedService) { - throw new AndroidRuntimeException("Tried waiting for the WebView Zygote Service to " + - "start running without first starting the service."); - } - - String serviceName; - synchronized (sLock) { - serviceName = getServiceNameLocked(); - } - try { - SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000); - } catch (TimeoutException e) { - Log.e(LOGTAG, "Timed out waiting for " + serviceName); - return; - } - - synchronized (sLock) { - connectToZygoteIfNeededLocked(); + stopZygoteLocked(); } } @GuardedBy("sLock") - private static String getServiceNameLocked() { - if (sPackage == null) - return null; - - if (Arrays.asList(Build.SUPPORTED_64_BIT_ABIS).contains( - sPackage.applicationInfo.primaryCpuAbi)) { - return WEBVIEW_ZYGOTE_SERVICE_64; + private static void stopZygoteLocked() { + if (sZygote != null) { + // Close the connection and kill the zygote process. This will not cause + // child processes to be killed by itself. But if this is called in response to + // setMultiprocessEnabled() or onWebViewProviderChanged(), the WebViewUpdater + // will kill all processes that depend on the WebView package. + sZygote.close(); + Process.killProcess(sZygote.getPid()); + sZygote = null; } - - return WEBVIEW_ZYGOTE_SERVICE_32; } @GuardedBy("sLock") @@ -196,14 +144,17 @@ public class WebViewZygote { return; } - final String serviceName = getServiceNameLocked(); - if (!SystemService.isRunning(serviceName)) { - Log.e(LOGTAG, serviceName + " is not running"); - return; - } - try { - sZygote = new ZygoteProcess(WEBVIEW_ZYGOTE_SOCKET, null); + sZygote = Process.zygoteProcess.startChildZygote( + "com.android.internal.os.WebViewZygoteInit", + "webview_zygote", + Process.WEBVIEW_ZYGOTE_UID, + Process.WEBVIEW_ZYGOTE_UID, + null, // gids + 0, // runtimeFlags + "webview_zygote", // seInfo + sPackage.applicationInfo.primaryCpuAbi, // abi + null); // instructionSet // All the work below is usually done by LoadedApk, but the zygote can't talk to // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so @@ -218,14 +169,21 @@ public class WebViewZygote { final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) : TextUtils.join(File.pathSeparator, zipPaths); - ZygoteProcess.waitForConnectionToZygote(WEBVIEW_ZYGOTE_SOCKET); + // In the case where the ApplicationInfo has been modified by the stub WebView, + // we need to use the original ApplicationInfo to determine what the original classpath + // would have been to use as a cache key. + LoadedApk.makePaths(null, false, sPackageOriginalAppInfo, zipPaths, null); + final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) : + TextUtils.join(File.pathSeparator, zipPaths); + + ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress()); Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath); - sZygote.preloadPackageForAbi(zip, librarySearchPath, sPackageCacheKey, + sZygote.preloadPackageForAbi(zip, librarySearchPath, cacheKey, Build.SUPPORTED_ABIS[0]); } catch (Exception e) { - Log.e(LOGTAG, "Error connecting to " + serviceName, e); - sZygote = null; + Log.e(LOGTAG, "Error connecting to webview zygote", e); + stopZygoteLocked(); } } } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 91e2f7d4ddd0..6c7455d35397 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3866,6 +3866,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te private void onTouchDown(MotionEvent ev) { mHasPerformedLongPress = false; mActivePointerId = ev.getPointerId(0); + hideSelector(); if (mTouchMode == TOUCH_MODE_OVERFLING) { // Stopped the fling. It is a scroll. @@ -5226,17 +5227,21 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } mRecycler.fullyDetachScrapViews(); + boolean selectorOnScreen = false; if (!inTouchMode && mSelectedPosition != INVALID_POSITION) { final int childIndex = mSelectedPosition - mFirstPosition; if (childIndex >= 0 && childIndex < getChildCount()) { positionSelector(mSelectedPosition, getChildAt(childIndex)); + selectorOnScreen = true; } } else if (mSelectorPosition != INVALID_POSITION) { final int childIndex = mSelectorPosition - mFirstPosition; if (childIndex >= 0 && childIndex < getChildCount()) { - positionSelector(INVALID_POSITION, getChildAt(childIndex)); + positionSelector(mSelectorPosition, getChildAt(childIndex)); + selectorOnScreen = true; } - } else { + } + if (!selectorOnScreen) { mSelectorRect.setEmpty(); } diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index e923223de81d..97500f29980b 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -26,6 +26,7 @@ import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageParser.PackageLite; +import android.content.pm.dex.DexMetadataHelper; import android.os.Environment; import android.os.FileUtils; import android.os.IBinder; @@ -663,6 +664,9 @@ public class PackageHelper { } } + // Include raw dex metadata files + sizeBytes += DexMetadataHelper.getPackageDexMetadataSize(pkg); + // Include all relevant native code sizeBytes += NativeLibraryHelper.sumNativeBinariesWithOverride(handle, abiOverride); diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 66475e445efa..bb5a0ad86dd4 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -71,10 +71,11 @@ public class RuntimeInit { public void uncaughtException(Thread t, Throwable e) { // Don't re-enter if KillApplicationHandler has already run if (mCrashing) return; - if (mApplicationObject == null) { - // The "FATAL EXCEPTION" string is still used on Android even though - // apps can set a custom UncaughtExceptionHandler that renders uncaught - // exceptions non-fatal. + + // mApplicationObject is null for non-zygote java programs (e.g. "am") + // There are also apps running with the system UID. We don't want the + // first clause in either of these two cases, only for system_server. + if (mApplicationObject == null && (Process.SYSTEM_UID == Process.myUid())) { Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e); } else { StringBuilder message = new StringBuilder(); @@ -229,7 +230,7 @@ public class RuntimeInit { * @param argv Argument vector for main() * @param classLoader the classLoader to load {@className} with */ - private static Runnable findStaticMain(String className, String[] argv, + protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<?> cl; diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java index cadb66ae6e08..32b580c2d277 100644 --- a/core/java/com/android/internal/os/WebViewZygoteInit.java +++ b/core/java/com/android/internal/os/WebViewZygoteInit.java @@ -18,9 +18,11 @@ package com.android.internal.os; import android.app.ApplicationLoaders; import android.net.LocalSocket; +import android.net.LocalServerSocket; import android.os.Build; import android.system.ErrnoException; import android.system.Os; +import android.system.OsConstants; import android.text.TextUtils; import android.util.Log; import android.webkit.WebViewFactory; @@ -118,18 +120,35 @@ class WebViewZygoteInit { } public static void main(String argv[]) { - sServer = new WebViewZygoteServer(); + Log.i(TAG, "Starting WebViewZygoteInit"); + + String socketName = null; + for (String arg : argv) { + Log.i(TAG, arg); + if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) { + socketName = arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length()); + } + } + if (socketName == null) { + throw new RuntimeException("No " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + " specified"); + } - // Zygote goes into its own process group. try { - Os.setpgid(0, 0); + Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); } catch (ErrnoException ex) { - throw new RuntimeException("Failed to setpgid(0,0)", ex); + throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex); } + sServer = new WebViewZygoteServer(); + final Runnable caller; try { - sServer.registerServerSocket("webview_zygote"); + sServer.registerServerSocketAtAbstractName(socketName); + + // Add the abstract socket to the FD whitelist so that the native zygote code + // can properly detach it after forking. + Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName); + // The select loop returns early in the child process after a fork and // loops forever in the zygote. caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS)); diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 03e5667666c1..e23cbf815b87 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -55,8 +55,8 @@ public final class Zygote { public static final int DISABLE_VERIFIER = 1 << 9; /** Only use oat files located in /system. Otherwise use dex/jar/apk . */ public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10; - /** Do not enfore hidden API access restrictions. */ - public static final int DISABLE_HIDDEN_API_CHECKS = 1 << 11; + /** Do enfore hidden API access restrictions. */ + public static final int ENABLE_HIDDEN_API_CHECKS = 1 << 11; /** Force generation of native debugging information for backtraces. */ public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12; @@ -71,6 +71,13 @@ public final class Zygote { private static final ZygoteHooks VM_HOOKS = new ZygoteHooks(); + /** + * An extraArg passed when a zygote process is forking a child-zygote, specifying a name + * in the abstract socket namespace. This socket name is what the new child zygote + * should listen for connections on. + */ + public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket="; + private Zygote() {} /** Called for some security initialization before any fork. */ @@ -102,6 +109,8 @@ public final class Zygote { * @param fdsToIgnore null-ok an array of ints, either null or holding * one or more POSIX file descriptor numbers that are to be ignored * in the file descriptor table check. + * @param startChildZygote if true, the new child process will itself be a + * new zygote process. * @param instructionSet null-ok the instruction set to use. * @param appDataDir null-ok the data directory of the app. * @@ -110,13 +119,13 @@ public final class Zygote { */ public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, - int[] fdsToIgnore, String instructionSet, String appDataDir) { + int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) { VM_HOOKS.preFork(); // Resets nice priority for zygote process. resetNicePriority(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, - fdsToIgnore, instructionSet, appDataDir); + fdsToIgnore, startChildZygote, instructionSet, appDataDir); // Enable tracing as soon as possible for the child process. if (pid == 0) { Trace.setTracingEnabled(true, runtimeFlags); @@ -130,7 +139,7 @@ public final class Zygote { native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, - int[] fdsToIgnore, String instructionSet, String appDataDir); + int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir); /** * Called to do any initialization before starting an application. @@ -162,9 +171,6 @@ public final class Zygote { */ public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { - // SystemServer is always allowed to use hidden APIs. - runtimeFlags |= DISABLE_HIDDEN_API_CHECKS; - VM_HOOKS.preFork(); // Resets nice priority for zygote process. resetNicePriority(); @@ -193,8 +199,8 @@ public final class Zygote { native protected static void nativeUnmountStorageOnInit(); private static void callPostForkChildHooks(int runtimeFlags, boolean isSystemServer, - String instructionSet) { - VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, instructionSet); + boolean isZygote, String instructionSet) { + VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet); } /** diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 6a87b1f4d3fd..a32fb4316d12 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -221,8 +221,8 @@ class ZygoteConnection { pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, - parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet, - parsedArgs.appDataDir); + parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote, + parsedArgs.instructionSet, parsedArgs.appDataDir); try { if (pid == 0) { @@ -233,7 +233,8 @@ class ZygoteConnection { IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; - return handleChildProc(parsedArgs, descriptors, childPipeFd); + return handleChildProc(parsedArgs, descriptors, childPipeFd, + parsedArgs.startChildZygote); } else { // In the parent. A pid < 0 indicates a failure and will be handled in // handleParentProc. @@ -415,6 +416,14 @@ class ZygoteConnection { boolean preloadDefault; /** + * Whether this is a request to start a zygote process as a child of this zygote. + * Set with --start-child-zygote. The remaining arguments must include the + * CHILD_ZYGOTE_SOCKET_NAME_ARG flag to indicate the abstract socket name that + * should be used for communication. + */ + boolean startChildZygote; + + /** * Constructs instance and parses args * @param args zygote command-line args * @throws IllegalArgumentException @@ -565,6 +574,8 @@ class ZygoteConnection { preloadPackageCacheKey = args[++curArg]; } else if (arg.equals("--preload-default")) { preloadDefault = true; + } else if (arg.equals("--start-child-zygote")) { + startChildZygote = true; } else { break; } @@ -587,6 +598,20 @@ class ZygoteConnection { remainingArgs = new String[args.length - curArg]; System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length); } + + if (startChildZygote) { + boolean seenChildSocketArg = false; + for (String arg : remainingArgs) { + if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) { + seenChildSocketArg = true; + break; + } + } + if (!seenChildSocketArg) { + throw new IllegalArgumentException("--start-child-zygote specified " + + "without " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG); + } + } } } @@ -739,9 +764,10 @@ class ZygoteConnection { * @param parsedArgs non-null; zygote args * @param descriptors null-ok; new file descriptors for stdio if available. * @param pipeFd null-ok; pipe for communication back to Zygote. + * @param isZygote whether this new child process is itself a new Zygote. */ private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, - FileDescriptor pipeFd) { + FileDescriptor pipeFd, boolean isZygote) { /** * By the time we get here, the native code has closed the two actual Zygote * socket connections, and substituted /dev/null in their place. The LocalSocket @@ -778,8 +804,13 @@ class ZygoteConnection { // Should not get here. throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned"); } else { - return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, - null /* classLoader */); + if (!isZygote) { + return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, + null /* classLoader */); + } else { + return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion, + parsedArgs.remainingArgs, null /* classLoader */); + } } } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 89a70fc0c9a2..a05454f53bf8 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -98,10 +98,6 @@ public class ZygoteInit { private static final String SOCKET_NAME_ARG = "--socket-name="; - /* Dexopt flag to disable hidden API access checks when dexopting SystemServer. - * Must be kept in sync with com.android.server.pm.Installer. */ - private static final int DEXOPT_DISABLE_HIDDEN_API_CHECKS = 1 << 10; - /** * Used to pre-load resources. */ @@ -569,10 +565,7 @@ public class ZygoteInit { if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { final String packageName = "*"; final String outputPath = null; - // Dexopt with a flag which lifts restrictions on hidden API usage. - // Offending methods would otherwise be re-verified at runtime and - // we want to avoid the performance overhead of that. - final int dexFlags = DEXOPT_DISABLE_HIDDEN_API_CHECKS; + final int dexFlags = 0; final String compilerFilter = systemServerFilter; final String uuid = StorageManager.UUID_PRIVATE_INTERNAL; final String seInfo = null; @@ -583,7 +576,8 @@ public class ZygoteInit { installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName, instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter, uuid, classLoaderContext, seInfo, false /* downgrade */, - targetSdkVersion); + targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null, + "server-dexopt"); } catch (RemoteException | ServiceSpecificException e) { // Ignore (but log), we need this on the classpath for fallback mode. Log.w(TAG, "Failed compiling classpath element for system server: " @@ -762,7 +756,7 @@ public class ZygoteInit { throw new RuntimeException("No ABI list supplied."); } - zygoteServer.registerServerSocket(socketName); + zygoteServer.registerServerSocketFromEnv(socketName); // In some configurations, we avoid preloading resources and classes eagerly. // In such cases, we will preload things prior to our first fork. if (!enableLazyPreload) { @@ -877,5 +871,16 @@ public class ZygoteInit { return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); } + /** + * The main function called when starting a child zygote process. This is used as an + * alternative to zygoteInit(), which skips calling into initialization routines that + * start the Binder threadpool. + */ + static final Runnable childZygoteInit( + int targetSdkVersion, String[] argv, ClassLoader classLoader) { + RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv); + return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader); + } + private static final native void nativeZygoteInit(); } diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java index 8baa15a058de..fecf9b9da5dd 100644 --- a/core/java/com/android/internal/os/ZygoteServer.java +++ b/core/java/com/android/internal/os/ZygoteServer.java @@ -44,9 +44,21 @@ class ZygoteServer { private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_"; + /** + * Listening socket that accepts new server connections. + */ private LocalServerSocket mServerSocket; /** + * Whether or not mServerSocket's underlying FD should be closed directly. + * If mServerSocket is created with an existing FD, closing the socket does + * not close the FD and it must be closed explicitly. If the socket is created + * with a name instead, then closing the socket will close the underlying FD + * and it should not be double-closed. + */ + private boolean mCloseSocketFd; + + /** * Set by the child process, immediately after a call to {@code Zygote.forkAndSpecialize}. */ private boolean mIsForkChild; @@ -59,11 +71,12 @@ class ZygoteServer { } /** - * Registers a server socket for zygote command connections + * Registers a server socket for zygote command connections. This locates the server socket + * file descriptor through an ANDROID_SOCKET_ environment variable. * * @throws RuntimeException when open fails */ - void registerServerSocket(String socketName) { + void registerServerSocketFromEnv(String socketName) { if (mServerSocket == null) { int fileDesc; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; @@ -78,6 +91,7 @@ class ZygoteServer { FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc); mServerSocket = new LocalServerSocket(fd); + mCloseSocketFd = true; } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); @@ -86,6 +100,22 @@ class ZygoteServer { } /** + * Registers a server socket for zygote command connections. This opens the server socket + * at the specified name in the abstract socket namespace. + */ + void registerServerSocketAtAbstractName(String socketName) { + if (mServerSocket == null) { + try { + mServerSocket = new LocalServerSocket(socketName); + mCloseSocketFd = false; + } catch (IOException ex) { + throw new RuntimeException( + "Error binding to abstract socket '" + socketName + "'", ex); + } + } + } + + /** * Waits for and accepts a single command connection. Throws * RuntimeException on failure. */ @@ -112,7 +142,7 @@ class ZygoteServer { if (mServerSocket != null) { FileDescriptor fd = mServerSocket.getFileDescriptor(); mServerSocket.close(); - if (fd != null) { + if (fd != null && mCloseSocketFd) { Os.close(fd); } } @@ -219,6 +249,11 @@ class ZygoteServer { Log.e(TAG, "Caught post-fork exception in child process.", e); throw e; } + } finally { + // Reset the child flag, in the event that the child process is a child- + // zygote. The flag will not be consulted this loop pass after the Runnable + // is returned. + mIsForkChild = false; } } } diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index 6af41a51f0dd..324f923674eb 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -256,7 +256,7 @@ public class MenuPopupHelper implements MenuHelper { final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity, mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK; if (hgrav == Gravity.RIGHT) { - xOffset += mAnchorView.getWidth(); + xOffset -= mAnchorView.getWidth(); } popup.setHorizontalOffset(xOffset); diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java index d9ca5be0502e..445379b1d9f4 100644 --- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java +++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java @@ -263,7 +263,6 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On mShownAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes); subPopup.setPresenterCallback(mPresenterCallback); subPopup.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(subMenu)); - subPopup.setGravity(mDropDownGravity); // Pass responsibility for handling onDismiss to the submenu. subPopup.setOnDismissListener(mOnDismissListener); @@ -273,8 +272,17 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On mMenu.close(false /* closeAllMenus */); // Show the new sub-menu popup at the same location as this popup. - final int horizontalOffset = mPopup.getHorizontalOffset(); + int horizontalOffset = mPopup.getHorizontalOffset(); final int verticalOffset = mPopup.getVerticalOffset(); + + // As xOffset of parent menu popup is subtracted with Anchor width for Gravity.RIGHT, + // So, again to display sub-menu popup in same xOffset, add the Anchor width. + final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity, + mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK; + if (hgrav == Gravity.RIGHT) { + horizontalOffset += mAnchorView.getWidth(); + } + if (subPopup.tryShow(horizontalOffset, verticalOffset)) { if (mPresenterCallback != null) { mPresenterCallback.onOpenSubMenu(subMenu); diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java index 8848e3939008..87fde4128ec5 100644 --- a/core/java/com/android/server/BootReceiver.java +++ b/core/java/com/android/server/BootReceiver.java @@ -161,7 +161,7 @@ public class BootReceiver extends BroadcastReceiver { .append("Revision: ") .append(SystemProperties.get("ro.revision", "")).append("\n") .append("Bootloader: ").append(Build.BOOTLOADER).append("\n") - .append("Radio: ").append(Build.RADIO).append("\n") + .append("Radio: ").append(Build.getRadioVersion()).append("\n") .append("Kernel: ") .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n")) .append("\n").toString(); diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp index 16591685848e..e8ef349f5b7a 100644 --- a/core/jni/android_os_VintfObject.cpp +++ b/core/jni/android_os_VintfObject.cpp @@ -32,10 +32,13 @@ static jclass gString; static jclass gHashMapClazz; static jmethodID gHashMapInit; static jmethodID gHashMapPut; +static jclass gLongClazz; +static jmethodID gLongValueOf; namespace android { using vintf::HalManifest; +using vintf::Level; using vintf::SchemaType; using vintf::VintfObject; using vintf::XmlConverter; @@ -154,6 +157,14 @@ static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) { return jMap; } +static jobject android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion(JNIEnv* env, jclass) { + std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest(); + if (manifest == nullptr || manifest->level() == Level::UNSPECIFIED) { + return nullptr; + } + return env->CallStaticObjectMethod(gLongClazz, gLongValueOf, static_cast<jlong>(manifest->level())); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gVintfObjectMethods[] = { @@ -163,6 +174,7 @@ static const JNINativeMethod gVintfObjectMethods[] = { {"getHalNamesAndVersions", "()[Ljava/lang/String;", (void*)android_os_VintfObject_getHalNamesAndVersions}, {"getSepolicyVersion", "()Ljava/lang/String;", (void*)android_os_VintfObject_getSepolicyVersion}, {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots}, + {"getTargetFrameworkCompatibilityMatrixVersion", "()Ljava/lang/Long;", (void*)android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion}, }; const char* const kVintfObjectPathName = "android/os/VintfObject"; @@ -175,6 +187,8 @@ int register_android_os_VintfObject(JNIEnv* env) gHashMapInit = GetMethodIDOrDie(env, gHashMapClazz, "<init>", "()V"); gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + gLongClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/Long")); + gLongValueOf = GetStaticMethodIDOrDie(env, gLongClazz, "valueOf", "(J)Ljava/lang/Long;"); return RegisterMethodsOrDie(env, kVintfObjectPathName, gVintfObjectMethods, NELEM(gVintfObjectMethods)); diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 560c38486bb9..93abc6359b57 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -664,7 +664,7 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) nativeData->mObject = val; gNativeDataCache = nullptr; ++gNumProxies; - if (++gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) { + if (gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) { ALOGW("Unexpectedly many live BinderProxies: %d\n", gNumProxies); gProxiesWarned = gNumProxies; } diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index fa86c7537d16..3f95cf460748 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -516,7 +516,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra jint mount_external, jstring java_se_info, jstring java_se_name, bool is_system_server, jintArray fdsToClose, - jintArray fdsToIgnore, + jintArray fdsToIgnore, bool is_child_zygote, jstring instructionSet, jstring dataDir) { SetSignalHandlers(); @@ -699,7 +699,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra UnsetChldSignalHandler(); env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, - is_system_server, instructionSet); + is_system_server, is_child_zygote, instructionSet); if (env->ExceptionCheck()) { RuntimeAbort(env, __LINE__, "Error calling post fork hooks."); } @@ -748,8 +748,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name, - jintArray fdsToClose, - jintArray fdsToIgnore, + jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote, jstring instructionSet, jstring appDataDir) { jlong capabilities = 0; @@ -786,13 +785,22 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( capabilities |= (1LL << CAP_BLOCK_SUSPEND); } + // If forking a child zygote process, that zygote will need to be able to change + // the UID and GID of processes it forks, as well as drop those capabilities. + if (is_child_zygote) { + capabilities |= (1LL << CAP_SETUID); + capabilities |= (1LL << CAP_SETGID); + capabilities |= (1LL << CAP_SETPCAP); + } + // Containers run without some capabilities, so drop any caps that are not // available. capabilities &= GetEffectiveCapabilityMask(env); return ForkAndSpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, mount_external, se_info, - se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir); + se_name, false, fdsToClose, fdsToIgnore, is_child_zygote == JNI_TRUE, + instructionSet, appDataDir); } static jint com_android_internal_os_Zygote_nativeForkSystemServer( @@ -803,7 +811,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( runtime_flags, rlimits, permittedCapabilities, effectiveCapabilities, MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL, - NULL, NULL, NULL); + NULL, false, NULL, NULL); if (pid > 0) { // The zygote process checks whether the child process has died or not. ALOGI("System server process %d has been created", pid); @@ -877,7 +885,7 @@ static const JNINativeMethod gMethods[] = { { "nativeSecurityInit", "()V", (void *) com_android_internal_os_Zygote_nativeSecurityInit }, { "nativeForkAndSpecialize", - "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I", + "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I", (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize }, { "nativeForkSystemServer", "(II[II[[IJJ)I", (void *) com_android_internal_os_Zygote_nativeForkSystemServer }, @@ -892,7 +900,7 @@ static const JNINativeMethod gMethods[] = { int register_com_android_internal_os_Zygote(JNIEnv* env) { gZygoteClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteClassName)); gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks", - "(IZLjava/lang/String;)V"); + "(IZZLjava/lang/String;)V"); return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods)); } diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 956b7249660f..1383bbd77b73 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -313,10 +313,12 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) { return false; } - // This is a local socket with an abstract address, we do not accept it. + // This is a local socket with an abstract address. Remove the leading NUL byte and + // add a human-readable "ABSTRACT/" prefix. if (unix_addr->sun_path[0] == '\0') { - LOG(ERROR) << "Unsupported AF_UNIX socket (fd=" << fd << ") with abstract address."; - return false; + *result = "ABSTRACT/"; + result->append(&unix_addr->sun_path[1], path_len - 1); + return true; } // If we're here, sun_path must refer to a null terminated filesystem diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto index ef6eb0913da4..f78ebcaa1f79 100644 --- a/core/proto/android/providers/settings.proto +++ b/core/proto/android/providers/settings.proto @@ -335,6 +335,7 @@ message GlobalSettingsProto { SettingProto uninstalled_instant_app_min_cache_period = 290; SettingProto uninstalled_instant_app_max_cache_period = 291; SettingProto unused_static_shared_lib_min_cache_period = 292; + SettingProto hidden_api_blacklist_exemptions = 293; } message SecureSettingsProto { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ada9bd76935e..4ea2d10c334f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -173,6 +173,10 @@ <protected-broadcast android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" /> <protected-broadcast + android:name="android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED" /> + <protected-broadcast + android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED" /> @@ -1765,19 +1769,29 @@ <permission android:name="android.permission.BIND_TELEPHONY_DATA_SERVICE" android:protectionLevel="signature" /> - <!-- Allows an application to manage embedded subscriptions (those on a eUICC) through - EuiccManager APIs. + <!-- Must be required by a NetworkService to ensure that only the + system can bind to it. + <p>Protection level: signature + @SystemApi + @hide + --> + <permission android:name="android.permission.BIND_TELEPHONY_NETWORK_SERVICE" + android:protectionLevel="signature" /> + + <!-- @SystemApi Allows an application to manage embedded subscriptions (those on a eUICC) + through EuiccManager APIs. <p>Protection level: signature|privileged|development - TODO(b/35851809): Mark this as a SystemApi and remove com. prefix. - @hide --> - <permission android:name="com.android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" + @hide + --> + <permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" android:protectionLevel="signature|privileged|development" /> - <!-- Must be required by an EuiccService to ensure that only the system can bind to it. + <!-- @SystemApi Must be required by an EuiccService to ensure that only the system can bind to + it. <p>Protection level: signature - TODO(b/35851809): Mark this as a SystemApi and remove com. prefix. - @hide --> - <permission android:name="com.android.permission.BIND_EUICC_SERVICE" + @hide + --> + <permission android:name="android.permission.BIND_EUICC_SERVICE" android:protectionLevel="signature" /> <!-- ================================== --> @@ -3599,6 +3613,11 @@ <permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE" android:protectionLevel="signature|development|instant|appop" /> + <!-- @SystemApi Allows an application to read the runtime profiles of other apps. + @hide <p>Not for use by third-party applications. --> + <permission android:name="android.permission.READ_RUNTIME_PROFILES" + android:protectionLevel="signature|privileged" /> + <application android:process="system" android:persistent="true" android:hasCode="false" diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a8a57000ba95..701ed556bc70 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3122,4 +3122,11 @@ <bool name="config_display_no_service_when_sim_unready">false</bool> <bool name="config_supportBluetoothPersistedState">true</bool> + + <!-- Cellular network service package name to bind to by default. --> + <string name="config_wwan_network_service_package" translatable="false">com.android.phone</string> + + <!-- IWLAN network service package name to bind to by default. If none is specified in an overlay, an + empty string is passed in --> + <string name="config_wlan_network_service_package" translatable="false"></string> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 08be23d94a59..0aec47e66aa1 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -266,6 +266,8 @@ <java-symbol type="bool" name="config_dynamic_bind_ims" /> <java-symbol type="string" name="config_wwan_data_service_package" /> <java-symbol type="string" name="config_wlan_data_service_package" /> + <java-symbol type="string" name="config_wwan_network_service_package" /> + <java-symbol type="string" name="config_wlan_network_service_package" /> <java-symbol type="bool" name="config_networkSamplingWakesDevice" /> <java-symbol type="bool" name="config_showMenuShortcutsWhenKeyboardPresent" /> <java-symbol type="bool" name="config_sip_wifi_only" /> diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index ab9912a438d4..c0a8acda628e 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1041,6 +1041,13 @@ </intent-filter> </activity> + <activity android:name="android.view.menu.ContextMenuActivity" android:label="ContextMenu" android:theme="@android:style/Theme.Material"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" /> + </intent-filter> + </activity> + <activity android:name="android.view.menu.MenuWith1Item" android:label="MenuWith1Item"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/core/tests/coretests/apks/install-split-base/Android.mk b/core/tests/coretests/apks/install-split-base/Android.mk new file mode 100644 index 000000000000..5b60e3167fc7 --- /dev/null +++ b/core/tests/coretests/apks/install-split-base/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := install_split_base + +include $(FrameworkCoreTests_BUILD_PACKAGE)
\ No newline at end of file diff --git a/core/tests/coretests/apks/install-split-base/AndroidManifest.xml b/core/tests/coretests/apks/install-split-base/AndroidManifest.xml new file mode 100644 index 000000000000..c2bfeddf32e3 --- /dev/null +++ b/core/tests/coretests/apks/install-split-base/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.frameworks.coretests.install_split" + android:isolatedSplits="true"> + + <application android:label="ClassloaderSplitApp"> + <activity android:name=".BaseActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java b/core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java new file mode 100644 index 000000000000..cb5760ceef8e --- /dev/null +++ b/core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java @@ -0,0 +1,23 @@ +/** + * 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 com.google.android.dexapis.splitapp; + +import android.app.Activity; + +/** Main activity */ +public class BaseActivity extends Activity { +} diff --git a/core/tests/coretests/apks/install-split-feature-a/Android.mk b/core/tests/coretests/apks/install-split-feature-a/Android.mk new file mode 100644 index 000000000000..0f37d16a7688 --- /dev/null +++ b/core/tests/coretests/apks/install-split-feature-a/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := install_split_feature_a + +LOCAL_USE_AAPT2 := true +LOCAL_AAPT_FLAGS += --custom-package com.google.android.dexapis.splitapp.feature_a +LOCAL_AAPT_FLAGS += --package-id 0x80 + +include $(FrameworkCoreTests_BUILD_PACKAGE)
\ No newline at end of file diff --git a/core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml b/core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml new file mode 100644 index 000000000000..3221c75ebe0c --- /dev/null +++ b/core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.frameworks.coretests.install_split" + featureSplit="feature_a"> + + <application> + <activity android:name=".feature_a.FeatureAActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java b/core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java new file mode 100644 index 000000000000..0af5f893164c --- /dev/null +++ b/core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java @@ -0,0 +1,23 @@ +/** + * 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 com.google.android.dexapis.splitapp.feature_a; + +import android.app.Activity; + +/** Main activity */ +public class FeatureAActivity extends Activity { +} diff --git a/core/tests/coretests/res/layout/context_menu.xml b/core/tests/coretests/res/layout/context_menu.xml new file mode 100644 index 000000000000..3b9e2bdb3130 --- /dev/null +++ b/core/tests/coretests/res/layout/context_menu.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** 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. +*/ +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:id="@+id/context_menu_target_ltr" + android:orientation="horizontal" + android:layoutDirection="ltr" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="50px" + android:layout_marginEnd="50px"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="LTR"/> + </LinearLayout> + + <LinearLayout + android:id="@+id/context_menu_target_rtl" + android:orientation="horizontal" + android:layoutDirection="rtl" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="50px" + android:layout_marginEnd="50px"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="RTL"/> + </LinearLayout> + +</LinearLayout> diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java new file mode 100644 index 000000000000..a18373654ea6 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java @@ -0,0 +1,235 @@ +/** + * 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.content.pm.dex; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PackageParser.ApkLite; +import android.content.pm.PackageParser.Package; +import android.content.pm.PackageParser.PackageLite; +import android.content.pm.PackageParser.PackageParserException; +import android.os.FileUtils; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.frameworks.coretests.R; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import libcore.io.IoUtils; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class DexMetadataHelperTest { + private static final String APK_FILE_EXTENSION = ".apk"; + private static final String DEX_METADATA_FILE_EXTENSION = ".dm"; + + private File mTmpDir = null; + + @Before + public void setUp() { + mTmpDir = IoUtils.createTemporaryDirectory("DexMetadataHelperTest"); + } + + @After + public void tearDown() { + if (mTmpDir != null) { + File[] files = mTmpDir.listFiles(); + for (File f : files) { + f.delete(); + } + } + } + + private File createDexMetadataFile(String apkFileName) throws IOException { + File dmFile = new File(mTmpDir, apkFileName.replace(APK_FILE_EXTENSION, + DEX_METADATA_FILE_EXTENSION)); + try (FileOutputStream fos = new FileOutputStream(dmFile)) { + try (ZipOutputStream zipOs = new ZipOutputStream(fos)) { + zipOs.putNextEntry(new ZipEntry("primary.prof")); + zipOs.closeEntry(); + } + } + return dmFile; + } + + private File copyApkToToTmpDir(String apkFileName, int apkResourceId) throws IOException { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + File outFile = new File(mTmpDir, apkFileName); + try (InputStream is = context.getResources().openRawResource(apkResourceId)) { + FileUtils.copyToFileOrThrow(is, outFile); + } + return outFile; + } + + @Test + public void testParsePackageWithDmFileValid() throws IOException, PackageParserException { + copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); + createDexMetadataFile("install_split_base.apk"); + Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + + Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); + assertEquals(1, packageDexMetadata.size()); + String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath); + assertNotNull(baseDexMetadata); + assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath)); + } + + @Test + public void testParsePackageSplitsWithDmFileValid() + throws IOException, PackageParserException { + copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); + copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a); + createDexMetadataFile("install_split_base.apk"); + createDexMetadataFile("install_split_feature_a.apk"); + Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + + Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); + assertEquals(2, packageDexMetadata.size()); + String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath); + assertNotNull(baseDexMetadata); + assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath)); + + String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]); + assertNotNull(splitDexMetadata); + assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0])); + } + + @Test + public void testParsePackageSplitsNoBaseWithDmFileValid() + throws IOException, PackageParserException { + copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); + copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a); + createDexMetadataFile("install_split_feature_a.apk"); + Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + + Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); + assertEquals(1, packageDexMetadata.size()); + + String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]); + assertNotNull(splitDexMetadata); + assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0])); + } + + @Test + public void testParsePackageWithDmFileInvalid() throws IOException { + copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); + File invalidDmFile = new File(mTmpDir, "install_split_base.dm"); + Files.createFile(invalidDmFile.toPath()); + try { + PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + DexMetadataHelper.validatePackageDexMetadata(pkg); + } catch (PackageParserException e) { + assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA); + } + } + + @Test + public void testParsePackageSplitsWithDmFileInvalid() + throws IOException, PackageParserException { + copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); + copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a); + createDexMetadataFile("install_split_base.apk"); + File invalidDmFile = new File(mTmpDir, "install_split_feature_a.dm"); + Files.createFile(invalidDmFile.toPath()); + + try { + PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + DexMetadataHelper.validatePackageDexMetadata(pkg); + } catch (PackageParserException e) { + assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA); + } + } + + @Test + public void testPackageWithDmFileNoMatch() throws IOException { + copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); + createDexMetadataFile("non_existent.apk"); + + try { + DexMetadataHelper.validateDexPaths(mTmpDir.list()); + fail("Should fail validation"); + } catch (IllegalStateException e) { + // expected. + } + } + + @Test + public void testPackageSplitsWithDmFileNoMatch() + throws IOException, PackageParserException { + copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); + copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a); + createDexMetadataFile("install_split_base.apk"); + createDexMetadataFile("install_split_feature_a.mistake.apk"); + + try { + DexMetadataHelper.validateDexPaths(mTmpDir.list()); + fail("Should fail validation"); + } catch (IllegalStateException e) { + // expected. + } + } + + @Test + public void testPackageSizeWithDmFile() + throws IOException, PackageParserException { + copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); + File dm = createDexMetadataFile("install_split_base.apk"); + PackageParser.PackageLite pkg = new PackageParser().parsePackageLite(mTmpDir, + 0 /* flags */); + + Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkg)); + } + + // This simulates the 'adb shell pm install' flow. + @Test + public void testPackageSizeWithPartialPackageLite() throws IOException, PackageParserException { + File base = copyApkToToTmpDir("install_split_base", R.raw.install_split_base); + File dm = createDexMetadataFile("install_split_base.apk"); + ApkLite baseApk = PackageParser.parseApkLite(base, 0); + PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null, + null, null); + Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkgLite)); + + } + + private static boolean isDexMetadataForApk(String dmaPath, String apkPath) { + return apkPath.substring(0, apkPath.length() - APK_FILE_EXTENSION.length()).equals( + dmaPath.substring(0, dmaPath.length() - DEX_METADATA_FILE_EXTENSION.length())); + } +} diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index ee276ef11957..757a70ca834e 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -413,7 +413,8 @@ public class SettingsBackupTest { Settings.Global.WTF_IS_FATAL, Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_CONFIG_ETAG, - Settings.Global.ZEN_MODE_RINGER_LEVEL); + Settings.Global.ZEN_MODE_RINGER_LEVEL, + Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS); private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS = newHashSet( diff --git a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java index 1e3ddf3226af..e69d1e7505d1 100644 --- a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java +++ b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java @@ -30,14 +30,15 @@ import android.telephony.UiccAccessRule; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Arrays; + @SmallTest @RunWith(AndroidJUnit4.class) public class EuiccProfileInfoTest { @Test public void testWriteToParcel() { EuiccProfileInfo p = - new EuiccProfileInfo.Builder() - .setIccid("21430000000000006587") + new EuiccProfileInfo.Builder("21430000000000006587") .setNickname("profile nickname") .setServiceProviderName("service provider") .setProfileName("profile name") @@ -50,9 +51,7 @@ public class EuiccProfileInfoTest { "45")) .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE) .setUiccAccessRule( - new UiccAccessRule[] { - new UiccAccessRule(new byte[] {}, "package", 12345L) - }) + Arrays.asList(new UiccAccessRule(new byte[] {}, "package", 12345L))) .build(); Parcel parcel = Parcel.obtain(); @@ -68,8 +67,7 @@ public class EuiccProfileInfoTest { @Test public void testWriteToParcelNullCarrierId() { EuiccProfileInfo p = - new EuiccProfileInfo.Builder() - .setIccid("21430000000000006587") + new EuiccProfileInfo.Builder("21430000000000006587") .setNickname("profile nickname") .setServiceProviderName("service provider") .setProfileName("profile name") @@ -77,9 +75,8 @@ public class EuiccProfileInfoTest { .setState(EuiccProfileInfo.PROFILE_STATE_ENABLED) .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE) .setUiccAccessRule( - new UiccAccessRule[] { - new UiccAccessRule(new byte[] {}, "package", 12345L) - }) + Arrays.asList(new UiccAccessRule(new byte[] {}, "package", 12345L)) + ) .build(); Parcel parcel = Parcel.obtain(); @@ -95,8 +92,7 @@ public class EuiccProfileInfoTest { @Test public void testBuilderAndGetters() { EuiccProfileInfo p = - new EuiccProfileInfo.Builder() - .setIccid("21430000000000006587") + new EuiccProfileInfo.Builder("21430000000000006587") .setNickname("profile nickname") .setProfileName("profile name") .setServiceProviderName("service provider") @@ -108,10 +104,7 @@ public class EuiccProfileInfoTest { .setState(EuiccProfileInfo.PROFILE_STATE_ENABLED) .setProfileClass(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL) .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE) - .setUiccAccessRule( - new UiccAccessRule[] { - new UiccAccessRule(new byte[0], null, 0) - }) + .setUiccAccessRule(Arrays.asList(new UiccAccessRule(new byte[0], null, 0))) .build(); assertEquals("21430000000000006587", p.getIccid()); @@ -130,14 +123,13 @@ public class EuiccProfileInfoTest { assertFalse(p.hasPolicyRule(EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE)); assertArrayEquals( new UiccAccessRule[] {new UiccAccessRule(new byte[0], null, 0)}, - p.getUiccAccessRules()); + p.getUiccAccessRules().toArray()); } @Test public void testBuilder_BasedOnAnotherProfile() { EuiccProfileInfo p = - new EuiccProfileInfo.Builder() - .setIccid("21430000000000006587") + new EuiccProfileInfo.Builder("21430000000000006587") .setNickname("profile nickname") .setProfileName("profile name") .setServiceProviderName("service provider") @@ -150,9 +142,7 @@ public class EuiccProfileInfoTest { .setProfileClass(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL) .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE) .setUiccAccessRule( - new UiccAccessRule[] { - new UiccAccessRule(new byte[0], null, 0) - }) + Arrays.asList(new UiccAccessRule(new byte[] {}, "package", 12345L))) .build(); EuiccProfileInfo copied = new EuiccProfileInfo.Builder(p).build(); @@ -164,8 +154,7 @@ public class EuiccProfileInfoTest { @Test public void testEqualsHashCode() { EuiccProfileInfo p = - new EuiccProfileInfo.Builder() - .setIccid("21430000000000006587") + new EuiccProfileInfo.Builder("21430000000000006587") .setNickname("profile nickname") .setProfileName("profile name") .setServiceProviderName("service provider") @@ -177,10 +166,7 @@ public class EuiccProfileInfoTest { .setState(EuiccProfileInfo.PROFILE_STATE_ENABLED) .setProfileClass(EuiccProfileInfo.PROFILE_STATE_ENABLED) .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE) - .setUiccAccessRule( - new UiccAccessRule[] { - new UiccAccessRule(new byte[0], null, 0) - }) + .setUiccAccessRule(Arrays.asList(new UiccAccessRule(new byte[0], null, 0))) .build(); assertTrue(p.equals(p)); @@ -229,13 +215,13 @@ public class EuiccProfileInfoTest { } @Test(expected = IllegalStateException.class) - public void testBuilderBuild_NoIccid() { - new EuiccProfileInfo.Builder().build(); + public void testBuilderBuild_IllegalIccid() { + new EuiccProfileInfo.Builder("abc").build(); } @Test(expected = IllegalArgumentException.class) public void testBuilderSetOperatorMccMnc_Illegal() { - new EuiccProfileInfo.Builder() + new EuiccProfileInfo.Builder("21430000000000006587") .setCarrierIdentifier(new CarrierIdentifier(new byte[] {1, 2, 3, 4}, null, null)); } diff --git a/core/tests/coretests/src/android/util/PollingCheck.java b/core/tests/coretests/src/android/util/PollingCheck.java new file mode 100644 index 000000000000..468b9b2a4864 --- /dev/null +++ b/core/tests/coretests/src/android/util/PollingCheck.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +import org.junit.Assert; + +/** + * Utility used for testing that allows to poll for a certain condition to happen within a timeout. + * + * Code copied from com.android.compatibility.common.util.PollingCheck + */ +public abstract class PollingCheck { + + private static final long DEFAULT_TIMEOUT = 3000; + private static final long TIME_SLICE = 50; + private final long mTimeout; + + /** + * The condition that the PollingCheck should use to proceed successfully. + */ + public interface PollingCheckCondition { + + /** + * @return Whether the polling condition has been met. + */ + boolean canProceed(); + } + + public PollingCheck(long timeout) { + mTimeout = timeout; + } + + protected abstract boolean check(); + + /** + * Start running the polling check. + */ + public void run() { + if (check()) { + return; + } + + long timeout = mTimeout; + while (timeout > 0) { + try { + Thread.sleep(TIME_SLICE); + } catch (InterruptedException e) { + Assert.fail("unexpected InterruptedException"); + } + + if (check()) { + return; + } + + timeout -= TIME_SLICE; + } + + Assert.fail("unexpected timeout"); + } + + /** + * Instantiate and start polling for a given condition with a default 3000ms timeout. + * + * @param condition The condition to check for success. + */ + public static void waitFor(final PollingCheckCondition condition) { + new PollingCheck(DEFAULT_TIMEOUT) { + @Override + protected boolean check() { + return condition.canProceed(); + } + }.run(); + } + + /** + * Instantiate and start polling for a given condition. + * + * @param timeout Time out in ms + * @param condition The condition to check for success. + */ + public static void waitFor(long timeout, final PollingCheckCondition condition) { + new PollingCheck(timeout) { + @Override + protected boolean check() { + return condition.canProceed(); + } + }.run(); + } +} + diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java new file mode 100644 index 000000000000..830b3d549773 --- /dev/null +++ b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java @@ -0,0 +1,54 @@ +/* + * 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.view.menu; + +import android.app.Activity; +import android.os.Bundle; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.View; + +import com.android.frameworks.coretests.R; + +public class ContextMenuActivity extends Activity { + + static final String LABEL_ITEM = "Item"; + static final String LABEL_SUBMENU = "Submenu"; + static final String LABEL_SUBITEM = "Subitem"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.context_menu); + registerForContextMenu(getTargetLtr()); + registerForContextMenu(getTargetRtl()); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + menu.add(LABEL_ITEM); + menu.addSubMenu(LABEL_SUBMENU).add(LABEL_SUBITEM); + } + + View getTargetLtr() { + return findViewById(R.id.context_menu_target_ltr); + } + + View getTargetRtl() { + return findViewById(R.id.context_menu_target_rtl); + } +} diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java new file mode 100644 index 000000000000..59d4e55d8d45 --- /dev/null +++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java @@ -0,0 +1,93 @@ +/* + * 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.view.menu; + +import android.content.Context; +import android.graphics.Point; +import android.support.test.filters.MediumTest; +import android.test.ActivityInstrumentationTestCase; +import android.util.PollingCheck; +import android.view.Display; +import android.view.View; +import android.view.WindowManager; +import android.widget.espresso.ContextMenuUtils; + +@MediumTest +public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenuActivity> { + + public ContextMenuTest() { + super("com.android.frameworks.coretests", ContextMenuActivity.class); + } + + public void testContextMenuPositionLtr() throws InterruptedException { + testMenuPosition(getActivity().getTargetLtr()); + } + + public void testContextMenuPositionRtl() throws InterruptedException { + testMenuPosition(getActivity().getTargetRtl()); + } + + private void testMenuPosition(View target) throws InterruptedException { + final int minScreenDimension = getMinScreenDimension(); + if (minScreenDimension < 320) { + // Assume there is insufficient room for the context menu to be aligned properly. + return; + } + + int offsetX = target.getWidth() / 2; + int offsetY = target.getHeight() / 2; + + getInstrumentation().runOnMainSync(() -> target.performLongClick(offsetX, offsetY)); + + PollingCheck.waitFor( + () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBMENU)); + + ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY); + + ContextMenuUtils.clickMenuItem(ContextMenuActivity.LABEL_SUBMENU); + + PollingCheck.waitFor( + () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBITEM)); + + if (minScreenDimension < getCascadingMenuTreshold()) { + // A non-cascading submenu should be displayed at the same location as its parent. + // Not testing cascading submenu position, as it is positioned differently. + ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY); + } + } + + /** + * Returns the minimum of the default display's width and height. + */ + private int getMinScreenDimension() { + final WindowManager windowManager = (WindowManager) getActivity().getSystemService( + Context.WINDOW_SERVICE); + final Display display = windowManager.getDefaultDisplay(); + final Point displaySize = new Point(); + display.getRealSize(displaySize); + return Math.min(displaySize.x, displaySize.y); + } + + /** + * Returns the minimum display size where cascading submenus are supported. + */ + private int getCascadingMenuTreshold() { + // Use the same dimension resource as in MenuPopupHelper.createPopup(). + return getActivity().getResources().getDimensionPixelSize( + com.android.internal.R.dimen.cascading_menus_min_smallest_width); + } +} diff --git a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java index c8218aa490f2..487a881082e7 100644 --- a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java +++ b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java @@ -17,25 +17,32 @@ package android.widget.espresso; import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.RootMatchers.withDecorView; import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; import static android.support.test.espresso.matcher.ViewMatchers.hasFocus; import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast; import static android.support.test.espresso.matcher.ViewMatchers.isEnabled; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.not; -import com.android.internal.view.menu.ListMenuItemView; - import android.support.test.espresso.NoMatchingRootException; import android.support.test.espresso.NoMatchingViewException; import android.support.test.espresso.ViewInteraction; import android.support.test.espresso.matcher.ViewMatchers; +import android.view.View; import android.widget.MenuPopupWindow.MenuDropDownListView; +import com.android.internal.view.menu.ListMenuItemView; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + /** * Espresso utility methods for the context menu. */ @@ -82,10 +89,15 @@ public final class ContextMenuUtils { private static void asssertContextMenuContainsItemWithEnabledState(String itemLabel, boolean enabled) { onContextMenu().check(matches( - hasDescendant(allOf( - isAssignableFrom(ListMenuItemView.class), - enabled ? isEnabled() : not(isEnabled()), - hasDescendant(withText(itemLabel)))))); + hasDescendant(getVisibleMenuItemMatcher(itemLabel, enabled)))); + } + + private static Matcher<View> getVisibleMenuItemMatcher(String itemLabel, boolean enabled) { + return allOf( + isAssignableFrom(ListMenuItemView.class), + hasDescendant(withText(itemLabel)), + enabled ? isEnabled() : not(isEnabled()), + isDisplayingAtLeast(90)); } /** @@ -107,4 +119,70 @@ public final class ContextMenuUtils { public static void assertContextMenuContainsItemDisabled(String itemLabel) { asssertContextMenuContainsItemWithEnabledState(itemLabel, false); } + + /** + * Asserts that the context menu window is aligned to a given view with a given offset. + * + * @param anchor Anchor view. + * @param offsetX x offset + * @param offsetY y offset. + * @throws AssertionError if the assertion fails + */ + public static void assertContextMenuAlignment(View anchor, int offsetX, int offsetY) { + int [] expectedLocation = new int[2]; + anchor.getLocationOnScreen(expectedLocation); + expectedLocation[0] += offsetX; + expectedLocation[1] += offsetY; + + final boolean rtl = anchor.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + + onContextMenu().check(matches(new TypeSafeMatcher<View>() { + @Override + public void describeTo(Description description) { + description.appendText("root view "); + description.appendText(rtl ? "right" : "left"); + description.appendText("="); + description.appendText(Integer.toString(offsetX)); + description.appendText(", top="); + description.appendText(Integer.toString(offsetY)); + } + + @Override + public boolean matchesSafely(View view) { + View rootView = view.getRootView(); + int [] actualLocation = new int[2]; + rootView.getLocationOnScreen(actualLocation); + if (rtl) { + actualLocation[0] += rootView.getWidth(); + } + return expectedLocation[0] == actualLocation[0] + && expectedLocation[1] == actualLocation[1]; + } + })); + } + + /** + * Check is the menu item is clickable (i.e. visible and enabled). + * + * @param itemLabel Label of the item. + * @return True if the menu item is clickable. + */ + public static boolean isMenuItemClickable(String itemLabel) { + try { + onContextMenu().check(matches( + hasDescendant(getVisibleMenuItemMatcher(itemLabel, true)))); + return true; + } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) { + return false; + } + } + + /** + * Click on a menu item with the specified label + * @param itemLabel Label of the item. + */ + public static void clickMenuItem(String itemLabel) { + onView(getVisibleMenuItemMatcher(itemLabel, true)) + .inRoot(withDecorView(hasFocus())).perform(click()); + } } diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk index 994131a22ab3..9b9e8113f234 100644 --- a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk +++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk @@ -29,13 +29,10 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES:= \ native.cpp -# All of the shard libraries we link against. -LOCAL_SHARED_LIBRARIES := liblog +LOCAL_LDLIBS := -llog LOCAL_CFLAGS += -Wall -Wextra -Werror -# Also need the JNI headers. -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) +LOCAL_SDK_VERSION := current include $(BUILD_SHARED_LIBRARY) diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp index 99cf587af2a6..fe32454aa10d 100644 --- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp +++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp @@ -15,12 +15,15 @@ */ #define LOG_TAG "pmtest32 native.cpp" -#include <utils/Log.h> +#include <android/log.h> #include <stdio.h> #include "jni.h" +#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) +#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) + static jint add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) { int result = a + b; diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk index 6c2679b30bfb..600a5d148740 100644 --- a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk +++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk @@ -30,14 +30,10 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES:= \ native.cpp -# All of the shared libraries we link against. -LOCAL_SHARED_LIBRARIES := \ - libutils liblog +LOCAL_LDLIBS := -llog LOCAL_CFLAGS += -Wall -Wextra -Werror -# Also need the JNI headers. -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) +LOCAL_SDK_VERSION := current include $(BUILD_SHARED_LIBRARY) diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp index 0b6d7501dcae..ad9e7469d1b8 100644 --- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp +++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp @@ -15,12 +15,15 @@ */ #define LOG_TAG "pmtest64 native.cpp" -#include <utils/Log.h> +#include <android/log.h> #include <stdio.h> #include "jni.h" +#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) +#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) + static jint add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) { int result = a + b; diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk index d668f29456c8..8e9ac6b5de95 100644 --- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk +++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk @@ -29,14 +29,10 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES:= \ native.cpp -# All of the shard libraries we link against. LOCAL_LDLIBS = -llog -LOCAL_SHARED_LIBRARIES := liblog LOCAL_CFLAGS += -Wall -Wextra -Werror -# Also need the JNI headers. -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) +LOCAL_SDK_VERSION := current include $(BUILD_SHARED_LIBRARY) diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp index 3947e21a77bd..5c5088f40a94 100644 --- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp +++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp @@ -15,12 +15,15 @@ */ #define LOG_TAG "pmtestdual native.cpp" -#include <utils/Log.h> +#include <android/log.h> #include <stdio.h> #include "jni.h" +#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) +#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) + static jint add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) { int result = a + b; diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 5b6577fd98aa..16c2b6894fc8 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -147,7 +147,6 @@ applications that come with the platform <permission name="android.permission.LOCAL_MAC_ADDRESS"/> <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> - <permission name="android.permission.PACKAGE_USAGE_STATS"/> <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/> <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/> <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> @@ -166,7 +165,7 @@ applications that come with the platform <permission name="android.permission.UPDATE_LOCK"/> <permission name="android.permission.WRITE_APN_SETTINGS"/> <permission name="android.permission.WRITE_SECURE_SETTINGS"/> - <permission name="com.android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/> + <permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/> <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/> <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/> </privapp-permissions> @@ -349,6 +348,7 @@ applications that come with the platform <permission name="android.permission.WRITE_DREAM_STATE"/> <permission name="android.permission.WRITE_MEDIA_STORAGE"/> <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + <permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/> </privapp-permissions> <privapp-permissions package="com.android.tv"> diff --git a/native/android/OWNERS b/native/android/OWNERS new file mode 100644 index 000000000000..11d4be43571e --- /dev/null +++ b/native/android/OWNERS @@ -0,0 +1,11 @@ +set noparent + +per-file libandroid_net.map.txt=ek@google.com +per-file libandroid_net.map.txt=jchalard@google.com +per-file libandroid_net.map.txt=lorenzo@google.com +per-file libandroid_net.map.txt=satk@google.com + +per-file net.c=ek@google.com +per-file net.c=jchalard@google.com +per-file net.c=lorenzo@google.com +per-file net.c=satk@google.com diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS new file mode 100644 index 000000000000..7057ce6cb6fe --- /dev/null +++ b/packages/CarrierDefaultApp/OWNERS @@ -0,0 +1,12 @@ +tgunn@google.com +breadley@google.com +hallliu@google.com +rgreenwalt@google.com +mpq@google.com +amitmahajan@google.com +fionaxu@google.com +jackyu@google.com +jminjie@google.com +satk@google.com +shuoq@google.com +refuhoo@google.com
\ No newline at end of file diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk index 88b85e078f45..12972f14514b 100644 --- a/packages/CtsShim/Android.mk +++ b/packages/CtsShim/Android.mk @@ -32,9 +32,10 @@ LOCAL_CERTIFICATE := PRESIGNED LOCAL_DEX_PREOPT := false LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64 -my_archs := arm x86 -my_src_arch := $(call get-prebuilt-src-arch, $(my_archs)) -LOCAL_SRC_FILES := apk/$(my_src_arch)/CtsShimPriv.apk +LOCAL_SRC_FILES_arm := apk/arm/CtsShimPriv.apk +LOCAL_SRC_FILES_arm64 := apk/arm/CtsShimPriv.apk +LOCAL_SRC_FILES_x86 := apk/x86/CtsShimPriv.apk +LOCAL_SRC_FILES_x86_64 := apk/x86/CtsShimPriv.apk include $(BUILD_PREBUILT) @@ -53,9 +54,10 @@ LOCAL_CERTIFICATE := PRESIGNED LOCAL_DEX_PREOPT := false LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64 -my_archs := arm x86 -my_src_arch := $(call get-prebuilt-src-arch, $(my_archs)) -LOCAL_SRC_FILES := apk/$(my_src_arch)/CtsShim.apk +LOCAL_SRC_FILES_arm := apk/arm/CtsShim.apk +LOCAL_SRC_FILES_arm64 := apk/arm/CtsShim.apk +LOCAL_SRC_FILES_x86 := apk/x86/CtsShim.apk +LOCAL_SRC_FILES_x86_64 := apk/x86/CtsShim.apk include $(BUILD_PREBUILT) diff --git a/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml b/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml new file mode 100644 index 000000000000..e14c99b61e2f --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml @@ -0,0 +1,24 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M17,20c-0.29,0 -0.56,-0.06 -0.76,-0.15 -0.71,-0.37 -1.21,-0.88 -1.71,-2.38 -0.51,-1.56 -1.47,-2.29 -2.39,-3 -0.79,-0.61 -1.61,-1.24 -2.32,-2.53C9.29,10.98 9,9.93 9,9c0,-2.8 2.2,-5 5,-5s5,2.2 5,5h2c0,-3.93 -3.07,-7 -7,-7S7,5.07 7,9c0,1.26 0.38,2.65 1.07,3.9 0.91,1.65 1.98,2.48 2.85,3.15 0.81,0.62 1.39,1.07 1.71,2.05 0.6,1.82 1.37,2.84 2.73,3.55 0.51,0.23 1.07,0.35 1.64,0.35 2.21,0 4,-1.79 4,-4h-2c0,1.1 -0.9,2 -2,2zM7.64,2.64L6.22,1.22C4.23,3.21 3,5.96 3,9s1.23,5.79 3.22,7.78l1.41,-1.41C6.01,13.74 5,11.49 5,9s1.01,-4.74 2.64,-6.36zM11.5,9c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5 -1.12,-2.5 -2.5,-2.5 -2.5,1.12 -2.5,2.5z"/> +</vector> diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml index 77df02bc5753..3460ecdb49d5 100644 --- a/packages/SettingsLib/res/values/arrays.xml +++ b/packages/SettingsLib/res/values/arrays.xml @@ -250,6 +250,19 @@ <item>Best Effort (Adaptive Bit Rate)</item> </string-array> + <!-- TODO: Enable for translation per b/73007419 --> + <!-- Summaries for Bluetooth Audio Active Device status. [CHAR LIMIT=50]--> + <string-array name="bluetooth_audio_active_device_summaries" translatable="false" > + <!-- Status message when the device is not Active. --> + <item></item> + <!-- Status message when the device is Active for Media and Phone. --> + <item>, active</item> + <!-- Status message when the device is Active for Media only. --> + <item>, active(media)</item> + <!-- Status message when the device is Active for Phone only. --> + <item>, active(phone)</item> + </string-array> + <!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] --> <string-array name="select_logd_size_titles"> <item>Off</item> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 660145142084..428f0b85b633 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -128,27 +128,27 @@ <!-- Bluetooth settings. Message when connecting to a device --> <string name="bluetooth_connecting">Connecting\u2026</string> <!-- Bluetooth settings. Message when connected to a device. [CHAR LIMIT=40] --> - <string name="bluetooth_connected">Connected</string> + <string name="bluetooth_connected">Connected<xliff:g id="active_device">%1$s</xliff:g></string> <!--Bluetooth settings screen, summary text under individual Bluetooth devices when pairing --> <string name="bluetooth_pairing">Pairing\u2026</string> <!-- Bluetooth settings. Message when connected to a device, except for phone audio. [CHAR LIMIT=40] --> - <string name="bluetooth_connected_no_headset">Connected (no phone)</string> + <string name="bluetooth_connected_no_headset">Connected (no phone)<xliff:g id="active_device">%1$s</xliff:g></string> <!-- Bluetooth settings. Message when connected to a device, except for media audio. [CHAR LIMIT=40] --> - <string name="bluetooth_connected_no_a2dp">Connected (no media)</string> + <string name="bluetooth_connected_no_a2dp">Connected (no media)<xliff:g id="active_device">%1$s</xliff:g></string> <!-- Bluetooth settings. Message when connected to a device, except for map. [CHAR LIMIT=40] --> - <string name="bluetooth_connected_no_map">Connected (no message access)</string> + <string name="bluetooth_connected_no_map">Connected (no message access)<xliff:g id="active_device">%1$s</xliff:g></string> <!-- Bluetooth settings. Message when connected to a device, except for phone/media audio. [CHAR LIMIT=40] --> - <string name="bluetooth_connected_no_headset_no_a2dp">Connected (no phone or media)</string> + <string name="bluetooth_connected_no_headset_no_a2dp">Connected (no phone or media)<xliff:g id="active_device">%1$s</xliff:g></string> <!-- Bluetooth settings. Message when connected to a device, showing remote device battery level. [CHAR LIMIT=NONE] --> - <string name="bluetooth_connected_battery_level">Connected, battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string> + <string name="bluetooth_connected_battery_level">Connected, battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string> <!-- Bluetooth settings. Message when connected to a device, except for phone audio, showing remote device battery level. [CHAR LIMIT=NONE] --> - <string name="bluetooth_connected_no_headset_battery_level">Connected (no phone), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string> + <string name="bluetooth_connected_no_headset_battery_level">Connected (no phone), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string> <!-- Bluetooth settings. Message when connected to a device, except for media audio, showing remote device battery level. [CHAR LIMIT=NONE] --> - <string name="bluetooth_connected_no_a2dp_battery_level">Connected (no media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string> + <string name="bluetooth_connected_no_a2dp_battery_level">Connected (no media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string> <!-- Bluetooth settings. Message when connected to a device, except for phone/media audio, showing remote device battery level. [CHAR LIMIT=NONE] --> - <string name="bluetooth_connected_no_headset_no_a2dp_battery_level">Connected (no phone or media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string> + <string name="bluetooth_connected_no_headset_no_a2dp_battery_level">Connected (no phone or media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string> <!-- Bluetooth settings. The user-visible string that is used whenever referring to the A2DP profile. --> <string name="bluetooth_profile_a2dp">Media audio</string> @@ -177,6 +177,11 @@ <!-- Bluetooth settings. Similar to bluetooth_profile_a2dp_high_quality, but used when the device supports high quality audio but we don't know which codec that will be used. --> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec">HD audio</string> + <!-- Bluetooth settings. The user-visible string that is used whenever referring to the Hearing Aid profile. --> + <string name="bluetooth_profile_hearing_aid">Hearing Aid</string> + <!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference when Hearing Aid is connected. --> + <string name="bluetooth_hearing_aid_profile_summary_connected">Connected to Hearing Aid</string> + <!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference when A2DP is connected. --> <string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string> <!-- Bluetooth settings. Connection options screen. The summary for the headset checkbox preference when headset is connected. --> @@ -214,6 +219,8 @@ for the HID checkbox preference that describes how checking it will set the HID profile as preferred. --> <string name="bluetooth_hid_profile_summary_use_for">Use for input</string> + <!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference that describes how checking it will set the Hearing Aid profile as preferred. --> + <string name="bluetooth_hearing_aid_profile_summary_use_for">Use for Hearing Aid</string> <!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] --> <string name="bluetooth_pairing_accept">Pair</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index fb0f75b522b3..e1ebbc4c166c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -940,60 +940,55 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> com.android.settingslib.Utils.formatPercentage(batteryLevel); } - // TODO: A temporary workaround solution using string description the device is active. - // Issue tracked by b/72317067 . - // An alternative solution would be visual indication. - // Intentionally not adding the strings to strings.xml for now: - // 1) If this is just a short-term solution, no need to waste translation effort - // 2) The number of strings with all possible combinations becomes enormously large. - // If string description becomes part of the final solution, we MUST NOT - // concatenate the strings here: this does not translate well. - String activeString = null; + // Prepare the string for the Active Device summary + String[] activeDeviceStringsArray = mContext.getResources().getStringArray( + R.array.bluetooth_audio_active_device_summaries); + String activeDeviceString = activeDeviceStringsArray[0]; // Default value: not active if (mIsActiveDeviceA2dp && mIsActiveDeviceHeadset) { - activeString = ", active"; + activeDeviceString = activeDeviceStringsArray[1]; // Active for Media and Phone } else { if (mIsActiveDeviceA2dp) { - activeString = ", active(media)"; + activeDeviceString = activeDeviceStringsArray[2]; // Active for Media only } if (mIsActiveDeviceHeadset) { - activeString = ", active(phone)"; + activeDeviceString = activeDeviceStringsArray[3]; // Active for Phone only } } - if (activeString == null) activeString = ""; if (profileConnected) { if (a2dpNotConnected && hfpNotConnected) { if (batteryLevelPercentageString != null) { return mContext.getString( R.string.bluetooth_connected_no_headset_no_a2dp_battery_level, - batteryLevelPercentageString) + activeString; + batteryLevelPercentageString, activeDeviceString); } else { - return mContext.getString(R.string.bluetooth_connected_no_headset_no_a2dp) + - activeString; + return mContext.getString(R.string.bluetooth_connected_no_headset_no_a2dp, + activeDeviceString); } } else if (a2dpNotConnected) { if (batteryLevelPercentageString != null) { return mContext.getString(R.string.bluetooth_connected_no_a2dp_battery_level, - batteryLevelPercentageString) + activeString; + batteryLevelPercentageString, activeDeviceString); } else { - return mContext.getString(R.string.bluetooth_connected_no_a2dp) + activeString; + return mContext.getString(R.string.bluetooth_connected_no_a2dp, + activeDeviceString); } } else if (hfpNotConnected) { if (batteryLevelPercentageString != null) { return mContext.getString(R.string.bluetooth_connected_no_headset_battery_level, - batteryLevelPercentageString) + activeString; + batteryLevelPercentageString, activeDeviceString); } else { - return mContext.getString(R.string.bluetooth_connected_no_headset) - + activeString; + return mContext.getString(R.string.bluetooth_connected_no_headset, + activeDeviceString); } } else { if (batteryLevelPercentageString != null) { return mContext.getString(R.string.bluetooth_connected_battery_level, - batteryLevelPercentageString) + activeString; + batteryLevelPercentageString, activeDeviceString); } else { - return mContext.getString(R.string.bluetooth_connected) + activeString; + return mContext.getString(R.string.bluetooth_connected, activeDeviceString); } } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java new file mode 100644 index 000000000000..8f9e4635bb4b --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java @@ -0,0 +1,235 @@ +/* + * 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.settingslib.bluetooth; + +import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothClass; +import android.bluetooth.BluetoothCodecConfig; +import android.bluetooth.BluetoothCodecStatus; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothUuid; +import android.content.Context; +import android.os.ParcelUuid; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settingslib.R; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class HearingAidProfile implements LocalBluetoothProfile { + private static final String TAG = "HearingAidProfile"; + private static boolean V = true; + + private Context mContext; + + private BluetoothHearingAid mService; + private boolean mIsProfileReady; + + private final LocalBluetoothAdapter mLocalAdapter; + private final CachedBluetoothDeviceManager mDeviceManager; + + static final String NAME = "HearingAid"; + private final LocalBluetoothProfileManager mProfileManager; + + // Order of this profile in device profiles list + private static final int ORDINAL = 1; + + // These callbacks run on the main thread. + private final class HearingAidServiceListener + implements BluetoothProfile.ServiceListener { + + public void onServiceConnected(int profile, BluetoothProfile proxy) { + if (V) Log.d(TAG,"Bluetooth service connected"); + mService = (BluetoothHearingAid) proxy; + // We just bound to the service, so refresh the UI for any connected HearingAid devices. + List<BluetoothDevice> deviceList = mService.getConnectedDevices(); + while (!deviceList.isEmpty()) { + BluetoothDevice nextDevice = deviceList.remove(0); + CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); + // we may add a new device here, but generally this should not happen + if (device == null) { + Log.w(TAG, "HearingAidProfile found new device: " + nextDevice); + device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); + } + device.onProfileStateChanged(HearingAidProfile.this, BluetoothProfile.STATE_CONNECTED); + device.refresh(); + } + mIsProfileReady=true; + } + + public void onServiceDisconnected(int profile) { + if (V) Log.d(TAG,"Bluetooth service disconnected"); + mIsProfileReady=false; + } + } + + public boolean isProfileReady() { + return mIsProfileReady; + } + + HearingAidProfile(Context context, LocalBluetoothAdapter adapter, + CachedBluetoothDeviceManager deviceManager, + LocalBluetoothProfileManager profileManager) { + mContext = context; + mLocalAdapter = adapter; + mDeviceManager = deviceManager; + mProfileManager = profileManager; + mLocalAdapter.getProfileProxy(context, new HearingAidServiceListener(), + BluetoothProfile.HEARING_AID); + } + + public boolean isConnectable() { + return true; + } + + public boolean isAutoConnectable() { + return true; + } + + public List<BluetoothDevice> getConnectedDevices() { + if (mService == null) return new ArrayList<BluetoothDevice>(0); + return mService.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.STATE_CONNECTING, + BluetoothProfile.STATE_DISCONNECTING}); + } + + public boolean connect(BluetoothDevice device) { + if (mService == null) return false; + return mService.connect(device); + } + + public boolean disconnect(BluetoothDevice device) { + if (mService == null) return false; + // Downgrade priority as user is disconnecting the hearing aid. + if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ + mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + } + return mService.disconnect(device); + } + + public int getConnectionStatus(BluetoothDevice device) { + if (mService == null) { + return BluetoothProfile.STATE_DISCONNECTED; + } + return mService.getConnectionState(device); + } + + public boolean isPreferred(BluetoothDevice device) { + if (mService == null) return false; + return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + } + + public int getPreferred(BluetoothDevice device) { + if (mService == null) return BluetoothProfile.PRIORITY_OFF; + return mService.getPriority(device); + } + + public void setPreferred(BluetoothDevice device, boolean preferred) { + if (mService == null) return; + if (preferred) { + if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { + mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + } + } else { + mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + } + } + + public int getVolume() { + if (mService == null) { + return 0; + } + return mService.getVolume(); + } + + public void setVolume(int volume) { + if (mService == null) { + return; + } + mService.setVolume(volume); + } + + public long getHiSyncId(BluetoothDevice device) { + if (mService == null) { + return BluetoothHearingAid.HI_SYNC_ID_INVALID; + } + return mService.getHiSyncId(device); + } + + public int getDeviceSide(BluetoothDevice device) { + if (mService == null) { + return BluetoothHearingAid.SIDE_LEFT; + } + return mService.getDeviceSide(device); + } + + public int getDeviceMode(BluetoothDevice device) { + if (mService == null) { + return BluetoothHearingAid.MODE_MONAURAL; + } + return mService.getDeviceMode(device); + } + + public String toString() { + return NAME; + } + + public int getOrdinal() { + return ORDINAL; + } + + public int getNameResource(BluetoothDevice device) { + return R.string.bluetooth_profile_hearing_aid; + } + + public int getSummaryResourceForDevice(BluetoothDevice device) { + int state = getConnectionStatus(device); + switch (state) { + case BluetoothProfile.STATE_DISCONNECTED: + return R.string.bluetooth_hearing_aid_profile_summary_use_for; + + case BluetoothProfile.STATE_CONNECTED: + return R.string.bluetooth_hearing_aid_profile_summary_connected; + + default: + return Utils.getConnectionStateSummary(state); + } + } + + public int getDrawableResource(BluetoothClass btClass) { + return R.drawable.ic_bt_hearing_aid; + } + + protected void finalize() { + if (V) Log.d(TAG, "finalize()"); + if (mService != null) { + try { + BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEARING_AID, + mService); + mService = null; + }catch (Throwable t) { + Log.w(TAG, "Error cleaning up Hearing Aid proxy", t); + } + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java index cda4e454fe74..5f7ba586fbad 100755..100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java @@ -194,8 +194,13 @@ public class LocalBluetoothAdapter { return mState; } - synchronized void setBluetoothStateInt(int state) { - mState = state; + void setBluetoothStateInt(int state) { + synchronized(this) { + if (mState == state) { + return; + } + mState = state; + } if (state == BluetoothAdapter.STATE_ON) { // if mProfileManager hasn't been constructed yet, it will diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index 991d9221c796..34a099cb7ea0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -21,6 +21,7 @@ import android.bluetooth.BluetoothA2dpSink; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHeadsetClient; +import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothHidHost; import android.bluetooth.BluetoothMap; import android.bluetooth.BluetoothMapClient; @@ -91,6 +92,7 @@ public class LocalBluetoothProfileManager { private final PbapServerProfile mPbapProfile; private final boolean mUsePbapPce; private final boolean mUseMapClient; + private HearingAidProfile mHearingAidProfile; /** * Mapping from profile name, e.g. "HEADSET" to profile object. @@ -143,10 +145,14 @@ public class LocalBluetoothProfileManager { //Create PBAP server profile if(DEBUG) Log.d(TAG, "Adding local PBAP profile"); + mPbapProfile = new PbapServerProfile(context); addProfile(mPbapProfile, PbapServerProfile.NAME, BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED); + mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this); + addProfile(mHearingAidProfile, HearingAidProfile.NAME, + BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete"); } @@ -254,6 +260,18 @@ public class LocalBluetoothProfileManager { "Warning: PBAP Client profile was previously added but the UUID is now missing."); } + //Hearing Aid Client + if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)) { + if (mHearingAidProfile == null) { + if(DEBUG) Log.d(TAG, "Adding local Hearing Aid profile"); + mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this); + addProfile(mHearingAidProfile, HearingAidProfile.NAME, + BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); + } + } else if (mHearingAidProfile != null) { + Log.w(TAG, "Warning: Hearing Aid profile was previously added but the UUID is now missing."); + } + mEventManager.registerProfileIntentReceiver(); // There is no local SDP record for HID and Settings app doesn't control PBAP Server. @@ -416,6 +434,10 @@ public class LocalBluetoothProfileManager { return mMapClientProfile; } + public HearingAidProfile getHearingAidProfile() { + return mHearingAidProfile; + } + /** * Fill in a list of LocalBluetoothProfile objects that are supported by * the local device and the remote device. @@ -515,6 +537,12 @@ public class LocalBluetoothProfileManager { removedProfiles.remove(mPbapClientProfile); } + if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid) && + mHearingAidProfile != null) { + profiles.add(mHearingAidProfile); + removedProfiles.remove(mHearingAidProfile); + } + if (DEBUG) { Log.d(TAG,"New Profiles" + profiles.toString()); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java index 4091ce1f173e..1481161bcb6c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java @@ -80,22 +80,12 @@ public class CachedBluetoothDeviceTest { doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel(); } - /** - * Test to verify the current test context object works so that we are not checking null - * against null - */ - @Test - public void testContextMock() { - assertThat(mContext.getString(R.string.bluetooth_connected)).isEqualTo("Connected"); - } - @Test public void testGetConnectionSummary_testSingleProfileConnectDisconnect() { // Test without battery level // Set PAN profile to be connected and test connection state summary mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); - assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString( - R.string.bluetooth_connected)); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected"); // Set PAN profile to be disconnected and test connection state summary mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); @@ -105,9 +95,7 @@ public class CachedBluetoothDeviceTest { mBatteryLevel = 10; // Set PAN profile to be connected and test connection state summary mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); - assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString( - R.string.bluetooth_connected_battery_level, - com.android.settingslib.Utils.formatPercentage(mBatteryLevel))); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, battery 10%"); // Set PAN profile to be disconnected and test connection state summary mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); @@ -118,8 +106,7 @@ public class CachedBluetoothDeviceTest { // Set PAN profile to be connected and test connection state summary mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); - assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString( - R.string.bluetooth_connected)); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected"); // Set PAN profile to be disconnected and test connection state summary mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); @@ -134,28 +121,23 @@ public class CachedBluetoothDeviceTest { mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); - assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString( - R.string.bluetooth_connected_battery_level, - com.android.settingslib.Utils.formatPercentage(mBatteryLevel))); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, battery 10%"); // Disconnect HFP only and test connection state summary mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); - assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString( - R.string.bluetooth_connected_no_headset_battery_level, - com.android.settingslib.Utils.formatPercentage(mBatteryLevel))); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( + "Connected (no phone), battery 10%"); // Disconnect A2DP only and test connection state summary mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); - assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString( - R.string.bluetooth_connected_no_a2dp_battery_level, - com.android.settingslib.Utils.formatPercentage(mBatteryLevel))); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( + "Connected (no media), battery 10%"); // Disconnect both HFP and A2DP and test connection state summary mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); - assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString( - R.string.bluetooth_connected_no_headset_no_a2dp_battery_level, - com.android.settingslib.Utils.formatPercentage(mBatteryLevel))); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( + "Connected (no phone or media), battery 10%"); // Disconnect all profiles and test connection state summary mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); @@ -163,6 +145,117 @@ public class CachedBluetoothDeviceTest { } @Test + public void testGetConnectionSummary_testSingleProfileActiveDeviceA2dp() { + // Test without battery level + // Set A2DP profile to be connected and test connection state summary + mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected"); + + // Set device as Active for A2DP and test connection state summary + mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(media)"); + + // Test with battery level + mBatteryLevel = 10; + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( + "Connected, battery 10%, active(media)"); + + // Set A2DP profile to be disconnected and test connection state summary + mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getConnectionSummary()).isNull(); + + // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level + mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + // Set A2DP profile to be connected, Active and test connection state summary + mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(media)"); + + // Set A2DP profile to be disconnected and test connection state summary + mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getConnectionSummary()).isNull(); + } + + @Test + public void testGetConnectionSummary_testSingleProfileActiveDeviceHfp() { + // Test without battery level + // Set HFP profile to be connected and test connection state summary + mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected"); + + // Set device as Active for HFP and test connection state summary + mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(phone)"); + + // Test with battery level + mBatteryLevel = 10; + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( + "Connected, battery 10%, active(phone)"); + + // Set HFP profile to be disconnected and test connection state summary + mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getConnectionSummary()).isNull(); + + // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level + mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + // Set HFP profile to be connected, Active and test connection state summary + mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(phone)"); + + // Set HFP profile to be disconnected and test connection state summary + mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getConnectionSummary()).isNull(); + } + + @Test + public void testGetConnectionSummary_testMultipleProfilesActiveDevice() { + // Test without battery level + // Set A2DP and HFP profiles to be connected and test connection state summary + mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected"); + + // Set device as Active for A2DP and HFP and test connection state summary + mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP); + mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active"); + + // Test with battery level + mBatteryLevel = 10; + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( + "Connected, battery 10%, active"); + + // Disconnect A2DP only and test connection state summary + mCachedDevice.setActiveDevice(false, BluetoothProfile.A2DP); + mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( + "Connected (no media), battery 10%, active(phone)"); + + // Disconnect HFP only and test connection state summary + mCachedDevice.setActiveDevice(false, BluetoothProfile.HEADSET); + mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( + "Connected (no phone), battery 10%, active(media)"); + + // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level + mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + // Set A2DP and HFP profiles to be connected, Active and test connection state summary + mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP); + mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET); + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active"); + + // Set A2DP and HFP profiles to be disconnected and test connection state summary + mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + assertThat(mCachedDevice.getConnectionSummary()).isNull(); + } + + @Test public void testDeviceName_testAliasNameAvailable() { when(mDevice.getAliasName()).thenReturn(DEVICE_ALIAS); when(mDevice.getName()).thenReturn(DEVICE_NAME); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index d256b12fe285..d32db8491b3a 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -924,6 +924,9 @@ class SettingsProtoDumpUtil { Settings.Global.CONTACTS_DATABASE_WAL_ENABLED, GlobalSettingsProto.CONTACTS_DATABASE_WAL_ENABLED); dumpSetting(s, p, + Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS, + GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS); + dumpSetting(s, p, Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, GlobalSettingsProto.MULTI_SIM_VOICE_CALL_SUBSCRIPTION); dumpSetting(s, p, diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 87971cb41f96..9268c8fa2a01 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -108,7 +108,7 @@ <uses-permission android:name="com.android.alarm.permission.SET_ALARM" /> <!-- Keyguard --> - <uses-permission android:name="com.android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" /> + <uses-permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" /> <uses-permission android:name="android.permission.CONTROL_KEYGUARD" /> <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 81b8622c548f..4320b6aa572c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -76,6 +76,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { @Override public void handleSetListening(boolean listening) { + if (mController == null) return; if (listening) { mController.addCallback(mCallback); } else { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index 9e265e2295c3..52b4c0ac4e1a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -235,6 +235,7 @@ public class DndTile extends QSTileImpl<BooleanState> { public void handleSetListening(boolean listening) { if (mListening == listening) return; mListening = listening; + if (mController == null) return; if (mListening) { mController.addCallback(mZenCallback); Prefs.registerListener(mContext, mPrefListener); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index b3ff4e5b890c..12daff1f12f9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -98,6 +98,8 @@ public class NfcTile extends QSTileImpl<BooleanState> { protected void handleUpdateState(BooleanState state, Object arg) { final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled); final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled); + + if (getAdapter() == null) return; state.value = getAdapter().isEnabled(); state.label = mContext.getString(R.string.quick_settings_nfc_label); state.icon = new DrawableIcon(state.value ? mEnable : mDisable); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 23702736b0db..fdbb260f39bd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -76,6 +76,7 @@ public class WifiTile extends QSTileImpl<SignalState> { @Override public void handleSetListening(boolean listening) { + if (mController == null) return; if (listening) { mController.addCallback(mSignalCallback); } else { diff --git a/proto/Android.bp b/proto/Android.bp index 95f453c3e523..f3811bdd7d81 100644 --- a/proto/Android.bp +++ b/proto/Android.bp @@ -6,6 +6,8 @@ java_library_static { }, srcs: ["src/**/*.proto"], no_framework_libs: true, + // Pin java_version until jarjar is certified to support later versions. http://b/72703434 + java_version: "1.8", target: { android: { jarjar_rules: "jarjar-rules.txt", diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index bff5c10d4e82..fd2ef18d624a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -30,6 +30,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_VPN; @@ -1260,11 +1261,7 @@ public class ConnectivityService extends IConnectivityManager.Stub for (Network network : networks) { nai = getNetworkAgentInfoForNetwork(network); nc = getNetworkCapabilitiesInternal(nai); - // nc is a copy of the capabilities in nai, so it's fine to mutate it - // TODO : don't remove the UIDs when communicating with processes - // that have the NETWORK_SETTINGS permission. if (nc != null) { - nc.setSingleUid(userId); result.put(network, nc); } } @@ -1332,7 +1329,9 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nai != null) { synchronized (nai) { if (nai.networkCapabilities != null) { - return new NetworkCapabilities(nai.networkCapabilities); + // TODO : don't remove the UIDs when communicating with processes + // that have the NETWORK_SETTINGS permission. + return networkCapabilitiesWithoutUids(nai.networkCapabilities); } } } @@ -1345,6 +1344,10 @@ public class ConnectivityService extends IConnectivityManager.Stub return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network)); } + private NetworkCapabilities networkCapabilitiesWithoutUids(NetworkCapabilities nc) { + return new NetworkCapabilities(nc).setUids(null); + } + @Override public NetworkState[] getAllNetworkState() { // Require internal since we're handing out IMSI details @@ -1354,6 +1357,10 @@ public class ConnectivityService extends IConnectivityManager.Stub for (Network network : getAllNetworks()) { final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); if (nai != null) { + // TODO (b/73321673) : NetworkState contains a copy of the + // NetworkCapabilities, which may contain UIDs of apps to which the + // network applies. Should the UIDs be cleared so as not to leak or + // interfere ? result.add(nai.getNetworkState()); } } @@ -4497,10 +4504,12 @@ public class ConnectivityService extends IConnectivityManager.Stub lp.ensureDirectlyConnectedRoutes(); // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network // satisfies mDefaultRequest. + final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), - new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, - new NetworkCapabilities(networkCapabilities), currentScore, + new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore, mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this); + // Make sure the network capabilities reflect what the agent info says. + nai.networkCapabilities = mixInCapabilities(nai, nc); synchronized (this) { nai.networkMonitor.systemReady = mSystemReady; } @@ -4729,6 +4738,11 @@ public class ConnectivityService extends IConnectivityManager.Stub } else { newNc.addCapability(NET_CAPABILITY_FOREGROUND); } + if (nai.isSuspended()) { + newNc.removeCapability(NET_CAPABILITY_NOT_SUSPENDED); + } else { + newNc.addCapability(NET_CAPABILITY_NOT_SUSPENDED); + } return newNc; } @@ -4909,7 +4923,7 @@ public class ConnectivityService extends IConnectivityManager.Stub releasePendingNetworkRequestWithDelay(pendingIntent); } - private static void callCallbackForRequest(NetworkRequestInfo nri, + private void callCallbackForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent, int notificationType, int arg1) { if (nri.messenger == null) { return; // Default request has no msgr @@ -4922,16 +4936,19 @@ public class ConnectivityService extends IConnectivityManager.Stub putParcelable(bundle, networkAgent.network); } switch (notificationType) { + case ConnectivityManager.CALLBACK_AVAILABLE: { + putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities)); + putParcelable(bundle, new LinkProperties(networkAgent.linkProperties)); + break; + } case ConnectivityManager.CALLBACK_LOSING: { msg.arg1 = arg1; break; } case ConnectivityManager.CALLBACK_CAP_CHANGED: { + // networkAgent can't be null as it has been accessed a few lines above. final NetworkCapabilities nc = - new NetworkCapabilities(networkAgent.networkCapabilities); - // TODO : don't remove the UIDs when communicating with processes - // that have the NETWORK_SETTINGS permission. - nc.setSingleUid(nri.mUid); + networkCapabilitiesWithoutUids(networkAgent.networkCapabilities); putParcelable(bundle, nc); break; } @@ -5464,6 +5481,10 @@ public class ConnectivityService extends IConnectivityManager.Stub if (networkAgent.getCurrentScore() != oldScore) { rematchAllNetworksAndRequests(networkAgent, oldScore); } + updateCapabilities(networkAgent.getCurrentScore(), networkAgent, + networkAgent.networkCapabilities); + // TODO (b/73132094) : remove this call once the few users of onSuspended and + // onResumed have been removed. notifyNetworkCallbacks(networkAgent, (state == NetworkInfo.State.SUSPENDED ? ConnectivityManager.CALLBACK_SUSPENDED : ConnectivityManager.CALLBACK_RESUMED)); @@ -5500,14 +5521,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, 0); - // Whether a network is currently suspended is also an important - // element of state to be transferred (it would not otherwise be - // delivered by any currently available mechanism). - if (nai.networkInfo.getState() == NetworkInfo.State.SUSPENDED) { - callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_SUSPENDED, 0); - } - callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_CAP_CHANGED, 0); - callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_IP_CHANGED, 0); } private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) { diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a07a982abc53..45a4dfb91bbf 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1438,7 +1438,9 @@ public class IpSecService extends IIpSecService.Stub { switch (config.getMode()) { case IpSecTransform.MODE_TRANSPORT: + break; case IpSecTransform.MODE_TUNNEL: + enforceNetworkStackPermission(); break; default: throw new IllegalArgumentException( @@ -1446,6 +1448,11 @@ public class IpSecService extends IIpSecService.Stub { } } + private void enforceNetworkStackPermission() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK, + "IpSecService"); + } + private void createOrUpdateTransform( IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord) throws RemoteException { @@ -1615,6 +1622,7 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void applyTunnelModeTransform( int tunnelResourceId, int direction, int transformResourceId) throws RemoteException { + enforceNetworkStackPermission(); checkDirection(direction); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 6743484b91c4..3a68311bf8b8 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -35,7 +35,6 @@ import android.os.UserHandle; import android.telephony.CellInfo; import android.telephony.CellLocation; import android.telephony.DisconnectCause; -import android.telephony.LocationAccessPolicy; import android.telephony.PhoneStateListener; import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; @@ -65,6 +64,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.NoSuchElementException; /** * Since phone process can be restarted, this class provides a centralized place @@ -91,11 +91,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { IBinder binder; + TelephonyRegistryDeathRecipient deathRecipient; + IPhoneStateListener callback; IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback; - int callerUid; - int callerPid; + int callerUserId; int events; @@ -119,7 +120,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { + " callback=" + callback + " onSubscriptionsChangedListenererCallback=" + onSubscriptionsChangedListenerCallback - + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId + + " callerUserId=" + callerUserId + " subId=" + subId + " phoneId=" + phoneId + " events=" + Integer.toHexString(events) + " canReadPhoneState=" + canReadPhoneState + "}"; } @@ -253,6 +254,21 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } }; + private class TelephonyRegistryDeathRecipient implements IBinder.DeathRecipient { + + private final IBinder binder; + + TelephonyRegistryDeathRecipient(IBinder binder) { + this.binder = binder; + } + + @Override + public void binderDied() { + if (DBG) log("binderDied " + binder); + remove(binder); + } + } + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -358,8 +374,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { public void addOnSubscriptionsChangedListener(String callingPackage, IOnSubscriptionsChangedListener callback) { int callerUserId = UserHandle.getCallingUserId(); - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); if (VDBG) { log("listen oscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId + " callback=" + callback @@ -382,29 +396,19 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - Record r; synchronized (mRecords) { // register - find_and_add: { - IBinder b = callback.asBinder(); - final int N = mRecords.size(); - for (int i = 0; i < N; i++) { - r = mRecords.get(i); - if (b == r.binder) { - break find_and_add; - } - } - r = new Record(); - r.binder = b; - mRecords.add(r); - if (DBG) log("listen oscl: add new record"); + IBinder b = callback.asBinder(); + Record r = add(b); + + if (r == null) { + return; } r.onSubscriptionsChangedListenerCallback = callback; r.callingPackage = callingPackage; - r.callerUid = Binder.getCallingUid(); - r.callerPid = Binder.getCallingPid(); + r.callerUserId = callerUserId; r.events = 0; r.canReadPhoneState = true; // permission has been enforced above if (DBG) { @@ -475,8 +479,6 @@ 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); if (VDBG) { log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events) + " notifyNow=" + notifyNow + " subId=" + subId + " myUserId=" @@ -501,28 +503,19 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + int phoneId = SubscriptionManager.getPhoneId(subId); synchronized (mRecords) { // register - Record r; - find_and_add: { - IBinder b = callback.asBinder(); - final int N = mRecords.size(); - for (int i = 0; i < N; i++) { - r = mRecords.get(i); - if (b == r.binder) { - break find_and_add; - } - } - r = new Record(); - r.binder = b; - mRecords.add(r); - if (DBG) log("listen: add new record"); + IBinder b = callback.asBinder(); + Record r = add(b); + + if (r == null) { + return; } r.callback = callback; r.callingPackage = callingPackage; - r.callerUid = Binder.getCallingUid(); - r.callerPid = Binder.getCallingPid(); + r.callerUserId = callerUserId; boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK | ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0; r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage); @@ -533,9 +526,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } else {//APP specify subID r.subId = subId; } - r.phoneId = SubscriptionManager.getPhoneId(r.subId); - - int phoneId = r.phoneId; + r.phoneId = phoneId; r.events = events; if (DBG) { log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId); @@ -580,10 +571,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if (DBG_LOC) log("listen: mCellLocation = " + mCellLocation[phoneId]); - if (checkLocationAccess(r)) { - r.callback.onCellLocationChanged( - new Bundle(mCellLocation[phoneId])); - } + r.callback.onCellLocationChanged( + new Bundle(mCellLocation[phoneId])); } catch (RemoteException ex) { remove(r.binder); } @@ -629,9 +618,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = " + mCellInfo.get(phoneId)); - if (checkLocationAccess(r)) { - r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); - } + r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); } catch (RemoteException ex) { remove(r.binder); } @@ -709,16 +696,57 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { return record.canReadPhoneState ? mCallIncomingNumber[phoneId] : ""; } + private Record add(IBinder binder) { + Record r; + + synchronized (mRecords) { + final int N = mRecords.size(); + for (int i = 0; i < N; i++) { + r = mRecords.get(i); + if (binder == r.binder) { + // Already existed. + return r; + } + } + r = new Record(); + r.binder = binder; + r.deathRecipient = new TelephonyRegistryDeathRecipient(binder); + + try { + binder.linkToDeath(r.deathRecipient, 0); + } catch (RemoteException e) { + if (VDBG) log("LinkToDeath remote exception sending to r=" + r + " e=" + e); + // Binder already died. Return null. + return null; + } + + mRecords.add(r); + if (DBG) log("add new record"); + } + + return r; + } + private void remove(IBinder binder) { synchronized (mRecords) { final int recordCount = mRecords.size(); for (int i = 0; i < recordCount; i++) { - if (mRecords.get(i).binder == binder) { + Record r = mRecords.get(i); + if (r.binder == binder) { if (DBG) { - Record r = mRecords.get(i); - log("remove: binder=" + binder + "r.callingPackage" + r.callingPackage - + "r.callback" + r.callback); + log("remove: binder=" + binder + " r.callingPackage " + r.callingPackage + + " r.callback " + r.callback); } + + if (r.deathRecipient != null) { + try { + binder.unlinkToDeath(r.deathRecipient, 0); + } catch (NoSuchElementException e) { + if (VDBG) log("UnlinkToDeath NoSuchElementException sending to r=" + + r + " e=" + e); + } + } + mRecords.remove(i); return; } @@ -984,15 +1012,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyCellInfoForSubscriber: subId=" + subId + " cellInfo=" + cellInfo); } - + int phoneId = SubscriptionManager.getPhoneId(subId); synchronized (mRecords) { - int phoneId = SubscriptionManager.getPhoneId(subId); if (validatePhoneId(phoneId)) { mCellInfo.set(phoneId, cellInfo); for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) && - idMatch(r.subId, subId, phoneId) && - checkLocationAccess(r)) { + idMatch(r.subId, subId, phoneId)) { try { if (DBG_LOC) { log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r); @@ -1075,8 +1101,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyCallForwardingChangedForSubscriber: subId=" + subId + " cfi=" + cfi); } + int phoneId = SubscriptionManager.getPhoneId(subId); synchronized (mRecords) { - int phoneId = SubscriptionManager.getPhoneId(subId); if (validatePhoneId(phoneId)) { mCallForwarding[phoneId] = cfi; for (Record r : mRecords) { @@ -1103,8 +1129,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!checkNotifyPermission("notifyDataActivity()" )) { return; } + int phoneId = SubscriptionManager.getPhoneId(subId); synchronized (mRecords) { - int phoneId = SubscriptionManager.getPhoneId(subId); if (validatePhoneId(phoneId)) { mDataActivity[phoneId] = state; for (Record r : mRecords) { @@ -1145,8 +1171,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType + " mRecords.size()=" + mRecords.size()); } + int phoneId = SubscriptionManager.getPhoneId(subId); synchronized (mRecords) { - int phoneId = SubscriptionManager.getPhoneId(subId); if (validatePhoneId(phoneId)) { boolean modified = false; if (state == TelephonyManager.DATA_CONNECTED) { @@ -1269,14 +1295,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyCellLocationForSubscriber: subId=" + subId + " cellLocation=" + cellLocation); } + int phoneId = SubscriptionManager.getPhoneId(subId); synchronized (mRecords) { - int phoneId = SubscriptionManager.getPhoneId(subId); if (validatePhoneId(phoneId)) { mCellLocation[phoneId] = cellLocation; for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) && - idMatch(r.subId, subId, phoneId) && - checkLocationAccess(r)) { + idMatch(r.subId, subId, phoneId)) { try { if (DBG_LOC) { log("notifyCellLocation: cellLocation=" + cellLocation @@ -1720,11 +1745,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { boolean valid = false; try { foregroundUser = ActivityManager.getCurrentUser(); - valid = UserHandle.getUserId(r.callerUid) == foregroundUser - && r.matchPhoneStateListenerEvent(events); + valid = r.callerUserId == foregroundUser && r.matchPhoneStateListenerEvent(events); if (DBG | DBG_LOC) { log("validateEventsAndUserLocked: valid=" + valid - + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser + + " r.callerUserId=" + r.callerUserId + " foregroundUser=" + foregroundUser + " r.events=" + r.events + " events=" + events); } } finally { @@ -1756,16 +1780,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - private boolean checkLocationAccess(Record r) { - long token = Binder.clearCallingIdentity(); - try { - return LocationAccessPolicy.canAccessCellLocation(mContext, - r.callingPackage, r.callerUid, r.callerPid); - } finally { - Binder.restoreCallingIdentity(token); - } - } - private void checkPossibleMissNotify(Record r, int phoneId) { int events = r.events; @@ -1813,9 +1827,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = " + mCellInfo.get(phoneId)); } - if (checkLocationAccess(r)) { - r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); - } + r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -1863,9 +1875,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = " + mCellLocation[phoneId]); - if (checkLocationAccess(r)) { - r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId])); - } + r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId])); } catch (RemoteException ex) { mRemoveList.add(r.binder); } diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 18b00ac21222..53285e6a07d7 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -566,14 +566,7 @@ public class Watchdog extends Thread { Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process"); } else { Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject); - for (int i=0; i<blockedCheckers.size(); i++) { - Slog.w(TAG, blockedCheckers.get(i).getName() + " stack trace:"); - StackTraceElement[] stackTrace - = blockedCheckers.get(i).getThread().getStackTrace(); - for (StackTraceElement element: stackTrace) { - Slog.w(TAG, " at " + element); - } - } + WatchdogDiagnostics.diagnoseCheckers(blockedCheckers); Slog.w(TAG, "*** GOODBYE!"); Process.killProcess(Process.myPid()); System.exit(10); diff --git a/services/core/java/com/android/server/WatchdogDiagnostics.java b/services/core/java/com/android/server/WatchdogDiagnostics.java new file mode 100644 index 000000000000..01db2d3a49c8 --- /dev/null +++ b/services/core/java/com/android/server/WatchdogDiagnostics.java @@ -0,0 +1,88 @@ +/* + * 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; + +import android.util.Log; +import android.util.LogWriter; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.Watchdog.HandlerChecker; + +import dalvik.system.AnnotatedStackTraceElement; +import dalvik.system.VMStack; + +import java.io.PrintWriter; +import java.util.List; + +/** + * Class to give diagnostic messages for Watchdogs. + */ +class WatchdogDiagnostics { + private static String getBlockedOnString(Object blockedOn) { + return String.format("- waiting to lock <0x%08x> (a %s)", + System.identityHashCode(blockedOn), blockedOn.getClass().getName()); + } + + private static String getLockedString(Object heldLock) { + return String.format("- locked <0x%08x> (a %s)", System.identityHashCode(heldLock), + heldLock.getClass().getName()); + } + + /** + * Print the annotated stack for the given thread. If the annotated stack cannot be retrieved, + * returns false. + */ + @VisibleForTesting + public static boolean printAnnotatedStack(Thread thread, PrintWriter out) { + AnnotatedStackTraceElement stack[] = VMStack.getAnnotatedThreadStackTrace(thread); + if (stack == null) { + return false; + } + out.println(thread.getName() + " annotated stack trace:"); + for (AnnotatedStackTraceElement element : stack) { + out.println(" at " + element.getStackTraceElement()); + if (element.getBlockedOn() != null) { + out.println(" " + getBlockedOnString(element.getBlockedOn())); + } + if (element.getHeldLocks() != null) { + for (Object held : element.getHeldLocks()) { + out.println(" " + getLockedString(held)); + } + } + } + return true; + } + + public static void diagnoseCheckers(final List<HandlerChecker> blockedCheckers) { + PrintWriter out = new PrintWriter(new LogWriter(Log.WARN, Watchdog.TAG, Log.LOG_ID_SYSTEM), + true); + for (int i=0; i<blockedCheckers.size(); i++) { + Thread blockedThread = blockedCheckers.get(i).getThread(); + if (printAnnotatedStack(blockedThread, out)) { + continue; + } + + // Fall back to "regular" stack trace, if necessary. + Slog.w(Watchdog.TAG, blockedThread.getName() + " stack trace:"); + StackTraceElement[] stackTrace = blockedThread.getStackTrace(); + for (StackTraceElement element : stackTrace) { + Slog.w(Watchdog.TAG, " at " + element); + } + } + } +} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f0d6757a7fee..6c60b74bbd24 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -533,6 +533,10 @@ public class ActivityManagerService extends IActivityManager.Stub // How long we wait until we timeout on key dispatching during instrumentation. static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000; + // Disable hidden API checks for the newly started instrumentation. + // Must be kept in sync with Am. + private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0; + // How long to wait in getAssistContextExtras for the activity and foreground services // to respond with the result. static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500; @@ -1738,6 +1742,9 @@ public class ActivityManagerService extends IActivityManager.Stub final ActivityManagerConstants mConstants; + // Encapsulates the global setting "hidden_api_blacklist_exemptions" + final HiddenApiBlacklist mHiddenApiBlacklist; + PackageManagerInternal mPackageManagerInt; // VoiceInteraction session ID that changes for each new request except when @@ -2687,6 +2694,42 @@ public class ActivityManagerService extends IActivityManager.Stub } } + /** + * Encapsulates the globla setting "hidden_api_blacklist_exemptions", including tracking the + * latest value via a content observer. + */ + static class HiddenApiBlacklist extends ContentObserver { + + private final Context mContext; + private boolean mBlacklistDisabled; + + public HiddenApiBlacklist(Handler handler, Context context) { + super(handler); + mContext = context; + } + + public void registerObserver() { + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS), + false, + this); + update(); + } + + private void update() { + mBlacklistDisabled = "*".equals(Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS)); + } + + boolean isDisabled() { + return mBlacklistDisabled; + } + + public void onChange(boolean selfChange) { + update(); + } + } + @VisibleForTesting public ActivityManagerService(Injector injector) { mInjector = injector; @@ -2716,6 +2759,7 @@ public class ActivityManagerService extends IActivityManager.Stub mUiHandler = injector.getUiHandler(null); mUserController = null; mVrController = null; + mHiddenApiBlacklist = null; } // Note: This method is invoked on the main thread but may need to attach various @@ -2848,6 +2892,8 @@ public class ActivityManagerService extends IActivityManager.Stub } }; + mHiddenApiBlacklist = new HiddenApiBlacklist(mHandler, mContext); + Watchdog.getInstance().addMonitor(this); Watchdog.getInstance().addThread(mHandler); } @@ -3628,6 +3674,7 @@ public class ActivityManagerService extends IActivityManager.Stub info.className = entryPoint; info.packageName = "android"; info.seInfoUser = SELinuxUtil.COMPLETE_STR; + info.targetSdkVersion = Build.VERSION.SDK_INT; ProcessRecord proc = startProcessLocked(processName, info /* info */, false /* knownToBeDead */, 0 /* intentFlags */, "" /* hostingType */, null /* hostingName */, true /* allowWhileBooting */, true /* isolated */, @@ -3770,6 +3817,13 @@ public class ActivityManagerService extends IActivityManager.Stub private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { + startProcessLocked(app, hostingType, hostingNameStr, false /* disableHiddenApiChecks */, + null /* abiOverride */, null /* entryPoint */, null /* entryPointArgs */); + } + + private final void startProcessLocked(ProcessRecord app, String hostingType, + String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride, + String entryPoint, String[] entryPointArgs) { long startTime = SystemClock.elapsedRealtime(); if (app.pid > 0 && app.pid != MY_PID) { checkTime(startTime, "startProcess: removing from pids map"); @@ -3890,10 +3944,12 @@ public class ActivityManagerService extends IActivityManager.Stub runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES; } - if (app.info.isAllowedToUseHiddenApi()) { - // This app is allowed to use undocumented and private APIs. Set - // up its runtime with the appropriate flag. - runtimeFlags |= Zygote.DISABLE_HIDDEN_API_CHECKS; + if (!app.info.isAllowedToUseHiddenApi() && + !disableHiddenApiChecks && + !mHiddenApiBlacklist.isDisabled()) { + // This app is not allowed to use undocumented and private APIs, or blacklisting is + // enabled. Set up its runtime with the appropriate flag. + runtimeFlags |= Zygote.ENABLE_HIDDEN_API_CHECKS; } String invokeWith = null; @@ -12413,6 +12469,12 @@ public class ActivityManagerService extends IActivityManager.Stub final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, String abiOverride) { + return addAppLocked(info, customProcess, isolated, false /* disableHiddenApiChecks */, + abiOverride); + } + + final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, + boolean disableHiddenApiChecks, String abiOverride) { ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName, @@ -12444,8 +12506,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); startProcessLocked(app, "added application", - customProcess != null ? customProcess : app.processName, abiOverride, - null /* entryPoint */, null /* entryPointArgs */); + customProcess != null ? customProcess : app.processName, disableHiddenApiChecks, + abiOverride, null /* entryPoint */, null /* entryPointArgs */); } return app; @@ -14164,6 +14226,7 @@ public class ActivityManagerService extends IActivityManager.Stub NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS); final boolean supportsLeanbackOnly = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK_ONLY); + mHiddenApiBlacklist.registerObserver(); // Transfer any global setting for forcing RTL layout, into a System Property SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0"); @@ -17480,6 +17543,7 @@ public class ActivityManagerService extends IActivityManager.Stub final long myTotalPss = mi.getTotalPss(); final long myTotalSwapPss = mi.getTotalSwappedOutPss(); totalPss += myTotalPss; + totalSwapPss += myTotalSwapPss; nativeProcTotalPss += myTotalPss; MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")", @@ -20108,7 +20172,10 @@ public class ActivityManagerService extends IActivityManager.Stub // Instrumentation can kill and relaunch even persistent processes forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId, "start instr"); - ProcessRecord app = addAppLocked(ai, defProcess, false, abiOverride); + boolean disableHiddenApiChecks = + (flags & INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0; + ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, + abiOverride); app.instr = activeInstr; activeInstr.mFinished = false; activeInstr.mRunningProcesses.add(app); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 59c0ed1393e6..254f4038538a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2729,7 +2729,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" specified then send to all users."); pw.println(" --receiver-permission <PERMISSION>: Require receiver to hold permission."); pw.println(" instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]"); - pw.println(" [--user <USER_ID> | current]"); + pw.println(" [--user <USER_ID> | current] [--no-hidden-api-checks]"); pw.println(" [--no-window-animation] [--abi <ABI>] <COMPONENT>"); pw.println(" Start an Instrumentation. Typically this target <COMPONENT> is in the"); pw.println(" form <TEST_PACKAGE>/<RUNNER_CLASS> or only <TEST_PACKAGE> if there"); @@ -2744,6 +2744,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" test runners."); pw.println(" --user <USER_ID> | current: Specify user instrumentation runs in;"); pw.println(" current user if not specified."); + pw.println(" --no-hidden-api-checks: disable restrictions on use of hidden API."); pw.println(" --no-window-animation: turn off window animations while running."); pw.println(" --abi <ABI>: Launch the instrumented process with the selected ABI."); pw.println(" This assumes that the process supports the selected ABI."); diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index d24f9c985ac4..0f8fc17047b9 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -172,7 +172,7 @@ public class KeepaliveTracker { } private int checkInterval() { - return mInterval >= 10 ? SUCCESS : ERROR_INVALID_INTERVAL; + return mInterval >= MIN_INTERVAL ? SUCCESS : ERROR_INVALID_INTERVAL; } private int isValid() { diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 85b70ca0ffcd..505480ea537e 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -285,7 +285,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { int delta = add ? +1 : -1; switch (request.type) { case REQUEST: - case TRACK_DEFAULT: mNumRequestNetworkRequests += delta; break; @@ -294,6 +293,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { mNumBackgroundNetworkRequests += delta; break; + case TRACK_DEFAULT: case LISTEN: break; @@ -384,12 +384,24 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { /** * Returns whether the network is a background network. A network is a background network if it - * is satisfying no foreground requests and at least one background request. (If it did not have - * a background request, it would be a speculative network that is only being kept up because - * it might satisfy a request if it validated). + * does not have the NET_CAPABILITY_FOREGROUND capability, which implies it is satisfying no + * foreground request, is not lingering (i.e. kept for a while after being outscored), and is + * not a speculative network (i.e. kept pending validation when validation would have it + * outscore another foreground network). That implies it is being kept up by some background + * request (otherwise it would be torn down), maybe the mobile always-on request. */ public boolean isBackgroundNetwork() { - return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0; + return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0 + && !isLingering(); + } + + /** + * Returns whether this network is currently suspended. A network is suspended if it is still + * connected but data temporarily fails to transfer. See {@link NetworkInfo.State#SUSPENDED} + * and {@link NetworkCapabilities#NET_CAPABILITY_NOT_SUSPENDED}. + */ + public boolean isSuspended() { + return networkInfo.getState() == NetworkInfo.State.SUSPENDED; } // Does this network satisfy request? @@ -458,7 +470,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public NetworkState getNetworkState() { synchronized (this) { - // Network objects are outwardly immutable so there is no point to duplicating. + // Network objects are outwardly immutable so there is no point in duplicating. // Duplicating also precludes sharing socket factories and connection pools. final String subscriberId = (networkMisc != null) ? networkMisc.subscriberId : null; return new NetworkState(new NetworkInfo(networkInfo), diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index e5f4282eefe0..0cba76ba7346 100644..100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -660,7 +660,8 @@ abstract class HdmiCecLocalDevice { @ServiceThreadOnly void startQueuedActions() { assertRunOnServiceThread(); - for (HdmiCecFeatureAction action : mActions) { + // Use copied action list in that start() may remove itself. + for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) { if (!action.started()) { Slog.i(TAG, "Starting queued action:" + action); action.start(); diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 2cd128d0171e..ab3c9996c59a 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -16,7 +16,9 @@ package com.android.server.pm; +import android.annotation.AppIdInt; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.PackageStats; import android.os.Build; @@ -58,9 +60,8 @@ public class Installer extends SystemService { public static final int DEXOPT_STORAGE_DE = 1 << 8; /** Indicates that dexopt is invoked from the background service. */ public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9; - /* Indicates that dexopt should not restrict access to private APIs. - * Must be kept in sync with com.android.internal.os.ZygoteInit. */ - public static final int DEXOPT_DISABLE_HIDDEN_API_CHECKS = 1 << 10; + /** Indicates that dexopt should restrict access to private APIs. */ + public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10; // NOTE: keep in sync with installd public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8; @@ -284,43 +285,45 @@ public class Installer extends SystemService { public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet, int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries, - @Nullable String seInfo, boolean downgrade, int targetSdkVersion) - throws InstallerException { + @Nullable String seInfo, boolean downgrade, int targetSdkVersion, + @Nullable String profileName, @Nullable String dexMetadataPath, + @Nullable String compilationReason) throws InstallerException { assertValidInstructionSet(instructionSet); if (!checkBeforeRemote()) return; try { mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade, - targetSdkVersion); + targetSdkVersion, profileName, dexMetadataPath, compilationReason); } catch (Exception e) { throw InstallerException.from(e); } } - public boolean mergeProfiles(int uid, String packageName) throws InstallerException { + public boolean mergeProfiles(int uid, String packageName, String profileName) + throws InstallerException { if (!checkBeforeRemote()) return false; try { - return mInstalld.mergeProfiles(uid, packageName); + return mInstalld.mergeProfiles(uid, packageName, profileName); } catch (Exception e) { throw InstallerException.from(e); } } - public boolean dumpProfiles(int uid, String packageName, String codePaths) + public boolean dumpProfiles(int uid, String packageName, String profileName, String codePath) throws InstallerException { if (!checkBeforeRemote()) return false; try { - return mInstalld.dumpProfiles(uid, packageName, codePaths); + return mInstalld.dumpProfiles(uid, packageName, profileName, codePath); } catch (Exception e) { throw InstallerException.from(e); } } - public boolean copySystemProfile(String systemProfile, int uid, String packageName) - throws InstallerException { + public boolean copySystemProfile(String systemProfile, int uid, String packageName, + String profileName) throws InstallerException { if (!checkBeforeRemote()) return false; try { - return mInstalld.copySystemProfile(systemProfile, uid, packageName); + return mInstalld.copySystemProfile(systemProfile, uid, packageName, profileName); } catch (Exception e) { throw InstallerException.from(e); } @@ -364,10 +367,10 @@ public class Installer extends SystemService { } } - public void clearAppProfiles(String packageName) throws InstallerException { + public void clearAppProfiles(String packageName, String profileName) throws InstallerException { if (!checkBeforeRemote()) return; try { - mInstalld.clearAppProfiles(packageName); + mInstalld.clearAppProfiles(packageName, profileName); } catch (Exception e) { throw InstallerException.from(e); } @@ -490,6 +493,36 @@ public class Installer extends SystemService { } } + public byte[] hashSecondaryDexFile(String dexPath, String packageName, int uid, + @Nullable String volumeUuid, int flags) throws InstallerException { + if (!checkBeforeRemote()) return new byte[0]; + try { + return mInstalld.hashSecondaryDexFile(dexPath, packageName, uid, volumeUuid, flags); + } catch (Exception e) { + throw InstallerException.from(e); + } + } + + public boolean createProfileSnapshot(int appId, String packageName, String profileName, + String classpath) throws InstallerException { + if (!checkBeforeRemote()) return false; + try { + return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath); + } catch (Exception e) { + throw InstallerException.from(e); + } + } + + public void destroyProfileSnapshot(String packageName, String profileName) + throws InstallerException { + if (!checkBeforeRemote()) return; + try { + mInstalld.destroyProfileSnapshot(packageName, profileName); + } catch (Exception e) { + throw InstallerException.from(e); + } + } + public void invalidateMounts() throws InstallerException { if (!checkBeforeRemote()) return; try { @@ -508,6 +541,17 @@ public class Installer extends SystemService { } } + public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId, + String profileName, String codePath, String dexMetadataPath) throws InstallerException { + if (!checkBeforeRemote()) return false; + try { + return mInstalld.prepareAppProfile(pkg, userId, appId, profileName, codePath, + dexMetadataPath); + } catch (Exception e) { + throw InstallerException.from(e); + } + } + private static void assertValidInstructionSet(String instructionSet) throws InstallerException { for (String abi : Build.SUPPORTED_ABIS) { diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 5dbd3caa7b79..b6804ba577e6 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -261,12 +261,13 @@ public class OtaDexoptService extends IOtaDexopt.Stub { String instructionSet, int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade, - int targetSdkVersion) + int targetSdkVersion, @Nullable String profileName, + @Nullable String dexMetadataPath, @Nullable String dexoptCompilationReason) throws InstallerException { final StringBuilder builder = new StringBuilder(); - // The version. Right now it's 4. - builder.append("4 "); + // The version. Right now it's 7. + builder.append("7 "); builder.append("dexopt"); @@ -283,6 +284,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub { encodeParameter(builder, seInfo); encodeParameter(builder, downgrade); encodeParameter(builder, targetSdkVersion); + encodeParameter(builder, profileName); + encodeParameter(builder, dexMetadataPath); + encodeParameter(builder, dexoptCompilationReason); commands.add(builder.toString()); } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 1f219c14dbec..51e035b1676d 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -20,6 +20,8 @@ import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageParser; +import android.content.pm.dex.ArtManager; +import android.content.pm.dex.DexMetadataHelper; import android.os.FileUtils; import android.os.PowerManager; import android.os.SystemClock; @@ -32,7 +34,6 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.pm.Installer.InstallerException; -import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.DexoptUtils; import com.android.server.pm.dex.PackageDexUsage; @@ -55,13 +56,14 @@ import static com.android.server.pm.Installer.DEXOPT_FORCE; import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE; import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE; import static com.android.server.pm.Installer.DEXOPT_IDLE_BACKGROUND_JOB; -import static com.android.server.pm.Installer.DEXOPT_DISABLE_HIDDEN_API_CHECKS; +import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT; -import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.getReasonName; + import static dalvik.system.DexFile.getSafeModeCompilerFilter; import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; @@ -211,12 +213,21 @@ public class PackageDexOptimizer { } } + String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]); + + String dexMetadataPath = null; + if (options.isDexoptInstallWithDexMetadata()) { + File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path)); + dexMetadataPath = dexMetadataFile == null + ? null : dexMetadataFile.getAbsolutePath(); + } + final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary() || packageUseInfo.isUsedByOtherApps(path); final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo, options.getCompilerFilter(), isUsedByOtherApps); final boolean profileUpdated = options.isCheckForProfileUpdates() && - isProfileUpdated(pkg, sharedGid, compilerFilter); + isProfileUpdated(pkg, sharedGid, profileName, compilerFilter); // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct // flags. @@ -225,7 +236,8 @@ public class PackageDexOptimizer { for (String dexCodeIsa : dexCodeInstructionSets) { int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid, - packageStats, options.isDowngrade()); + packageStats, options.isDowngrade(), profileName, dexMetadataPath, + options.getCompilationReason()); // The end result is: // - FAILED if any path failed, // - PERFORMED if at least one path needed compilation, @@ -249,7 +261,8 @@ public class PackageDexOptimizer { @GuardedBy("mInstallLock") private int dexOptPath(PackageParser.Package pkg, String path, String isa, String compilerFilter, boolean profileUpdated, String classLoaderContext, - int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade) { + int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade, + String profileName, String dexMetadataPath, int compilationReason) { int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext, profileUpdated, downgrade); if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) { @@ -275,7 +288,8 @@ public class PackageDexOptimizer { // primary dex files. mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags, compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo, - false /* downgrade*/, pkg.applicationInfo.targetSdkVersion); + false /* downgrade*/, pkg.applicationInfo.targetSdkVersion, + profileName, dexMetadataPath, getReasonName(compilationReason)); if (packageStats != null) { long endTime = System.currentTimeMillis(); @@ -386,7 +400,7 @@ public class PackageDexOptimizer { // Note this trades correctness for performance since the resulting slow down is // unacceptable in some cases until b/64530081 is fixed. String classLoaderContext = SKIP_SHARED_LIBRARY_CHECK; - + int reason = options.getCompilationReason(); try { for (String isa : dexUseInfo.getLoaderIsas()) { // Reuse the same dexopt path as for the primary apks. We don't need all the @@ -396,7 +410,8 @@ public class PackageDexOptimizer { mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0, /*oatDir*/ null, dexoptFlags, compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser, - options.isDowngrade(), info.targetSdkVersion); + options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null, + /*dexMetadataPath*/ null, getReasonName(reason)); } return DEX_OPT_PERFORMED; @@ -506,15 +521,17 @@ public class PackageDexOptimizer { private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) { int flags = info.flags; boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; - // Profile guide compiled oat files should not be public. + // Profile guide compiled oat files should not be public unles they are based + // on profiles from dex metadata archives. + // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that + // the user does not have an existing profile. boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter); - boolean isPublic = !info.isForwardLocked() && !isProfileGuidedFilter; + boolean isPublic = !info.isForwardLocked() && + (!isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata()); int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0; - // System apps are invoked with a runtime flag which exempts them from - // restrictions on hidden API usage. We dexopt with the same runtime flag - // otherwise offending methods would have to be re-verified at runtime - // and we want to avoid the performance overhead of that. - int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? DEXOPT_DISABLE_HIDDEN_API_CHECKS : 0; + // Some apps are executed with restrictions on hidden API usage. If this app is one + // of them, pass a flag to dexopt to enable the same restrictions during compilation. + int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? 0 : DEXOPT_ENABLE_HIDDEN_API_CHECKS; int dexFlags = (isPublic ? DEXOPT_PUBLIC : 0) | (debuggable ? DEXOPT_DEBUGGABLE : 0) @@ -550,14 +567,15 @@ public class PackageDexOptimizer { * current profile and the reference profile will be merged and subsequent calls * may return a different result. */ - private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String compilerFilter) { + private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String profileName, + String compilerFilter) { // Check if we are allowed to merge and if the compiler filter is profile guided. if (!isProfileGuidedCompilerFilter(compilerFilter)) { return false; } // Merge profiles. It returns whether or not there was an updated in the profile info. try { - return mInstaller.mergeProfiles(uid, pkg.packageName); + return mInstaller.mergeProfiles(uid, pkg.packageName, profileName); } catch (InstallerException e) { Slog.w(TAG, "Failed to merge profiles", e); } @@ -636,8 +654,8 @@ public class PackageDexOptimizer { if ((flags & DEXOPT_IDLE_BACKGROUND_JOB) == DEXOPT_IDLE_BACKGROUND_JOB) { flagsList.add("idle_background_job"); } - if ((flags & DEXOPT_DISABLE_HIDDEN_API_CHECKS) == DEXOPT_DISABLE_HIDDEN_API_CHECKS) { - flagsList.add("disable_hidden_api_checks"); + if ((flags & DEXOPT_ENABLE_HIDDEN_API_CHECKS) == DEXOPT_ENABLE_HIDDEN_API_CHECKS) { + flagsList.add("enable_hidden_api_checks"); } return String.join(",", flagsList); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index bf86300a93a8..7204aa1a76e3 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -17,10 +17,12 @@ package com.android.server.pm; import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED; +import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_DEX_METADATA; import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR; import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; +import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.O_WRONLY; @@ -94,6 +96,7 @@ import com.android.internal.util.Preconditions; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter; +import android.content.pm.dex.DexMetadataHelper; import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; @@ -259,6 +262,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // entries like "lost+found". if (file.isDirectory()) return false; if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false; + if (DexMetadataHelper.isDexMetadataFile(file)) return false; return true; } }; @@ -944,6 +948,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mInstallerPackageName, mInstallerUid, user, mCertificates); } + private static void maybeRenameFile(File from, File to) throws PackageManagerException { + if (!from.equals(to)) { + if (!from.renameTo(to)) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Could not rename file " + from + " to " + to); + } + } + } + /** * Validate install by confirming that all application packages are have * consistent package name, version code, and signing certificates. @@ -988,6 +1001,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged"); } + // Verify that all staged packages are internally consistent final ArraySet<String> stagedSplits = new ArraySet<>(); for (File addedFile : addedFiles) { @@ -1022,9 +1036,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Take this opportunity to enforce uniform naming final String targetName; if (apk.splitName == null) { - targetName = "base.apk"; + targetName = "base" + APK_FILE_EXTENSION; } else { - targetName = "split_" + apk.splitName + ".apk"; + targetName = "split_" + apk.splitName + APK_FILE_EXTENSION; } if (!FileUtils.isValidExtFilename(targetName)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, @@ -1032,9 +1046,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } final File targetFile = new File(mResolvedStageDir, targetName); - if (!addedFile.equals(targetFile)) { - addedFile.renameTo(targetFile); - } + maybeRenameFile(addedFile, targetFile); // Base is coming from session if (apk.splitName == null) { @@ -1042,6 +1054,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } mResolvedStagedFiles.add(targetFile); + + final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile); + if (dexMetadataFile != null) { + if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Invalid filename: " + dexMetadataFile); + } + final File targetDexMetadataFile = new File(mResolvedStageDir, + DexMetadataHelper.buildDexMetadataPathForApk(targetName)); + mResolvedStagedFiles.add(targetDexMetadataFile); + maybeRenameFile(dexMetadataFile, targetDexMetadataFile); + } } if (removeSplitList.size() > 0) { @@ -1099,6 +1123,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (mResolvedBaseFile == null) { mResolvedBaseFile = new File(appInfo.getBaseCodePath()); mResolvedInheritedFiles.add(mResolvedBaseFile); + // Inherit the dex metadata if present. + final File baseDexMetadataFile = + DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile); + if (baseDexMetadataFile != null) { + mResolvedInheritedFiles.add(baseDexMetadataFile); + } } // Inherit splits if not overridden @@ -1109,6 +1139,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final boolean splitRemoved = removeSplitList.contains(splitName); if (!stagedSplits.contains(splitName) && !splitRemoved) { mResolvedInheritedFiles.add(splitFile); + // Inherit the dex metadata if present. + final File splitDexMetadataFile = + DexMetadataHelper.findDexMetadataForFile(splitFile); + if (splitDexMetadataFile != null) { + mResolvedInheritedFiles.add(splitDexMetadataFile); + } } } } @@ -1167,7 +1203,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** * Calculate the final install footprint size, combining both staged and * existing APKs together and including unpacked native code from both. - */ + */ private long calculateInstalledSize() throws PackageManagerException { Preconditions.checkNotNull(mResolvedBaseFile); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4454c71ab896..900e18873193 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -106,8 +106,6 @@ import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILUR import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS; import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; -import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter; - import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; @@ -179,6 +177,9 @@ import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; import android.content.pm.VersionedPackage; +import android.content.pm.dex.ArtManager; +import android.content.pm.dex.DexMetadataHelper; +import android.content.pm.dex.IArtManager; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; @@ -285,13 +286,14 @@ import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.PermissionsState.PermissionState; import com.android.server.pm.Settings.DatabaseVersion; import com.android.server.pm.Settings.VersionInfo; +import com.android.server.pm.dex.ArtManagerService; +import com.android.server.pm.dex.DexLogger; import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.PackageDexUsage; import com.android.server.storage.DeviceStorageMonitorInternal; import dalvik.system.CloseGuard; -import dalvik.system.DexFile; import dalvik.system.VMRuntime; import libcore.io.IoUtils; @@ -573,6 +575,7 @@ public class PackageManagerService extends IPackageManager.Stub } // Compilation reasons. + public static final int REASON_UNKNOWN = -1; public static final int REASON_FIRST_BOOT = 0; public static final int REASON_BOOT = 1; public static final int REASON_INSTALL = 2; @@ -960,6 +963,8 @@ public class PackageManagerService extends IPackageManager.Stub final PackageInstallerService mInstallerService; + final ArtManagerService mArtManagerService; + private final PackageDexOptimizer mPackageDexOptimizer; // DexManager handles the usage of dex files (e.g. secondary files, whether or not a package // is used by other apps). @@ -2461,7 +2466,11 @@ public class PackageManagerService extends IPackageManager.Stub mInstaller = installer; mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context, "*dexopt*"); - mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock); + DexManager.Listener dexManagerListener = DexLogger.getListener(this, + installer, mInstallLock); + mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock, + dexManagerListener); + mArtManagerService = new ArtManagerService(this, installer, mInstallLock); mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper()); mOnPermissionChangeListeners = new OnPermissionChangeListeners( @@ -9702,7 +9711,7 @@ public class PackageManagerService extends IPackageManager.Stub final long startTime = System.nanoTime(); final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */, - getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT), + causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT, false /* bootComplete */); final int elapsedTimeSeconds = @@ -9729,7 +9738,7 @@ public class PackageManagerService extends IPackageManager.Stub * and {@code numberOfPackagesFailed}. */ private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog, - final String compilerFilter, boolean bootComplete) { + final int compilationReason, boolean bootComplete) { int numberOfPackagesVisited = 0; int numberOfPackagesOptimized = 0; @@ -9753,7 +9762,8 @@ public class PackageManagerService extends IPackageManager.Stub // PackageDexOptimizer to prevent this happening on first boot. The issue // is that we don't have a good way to say "do this only once". if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), - pkg.applicationInfo.uid, pkg.packageName)) { + pkg.applicationInfo.uid, pkg.packageName, + ArtManager.getProfileName(null))) { Log.e(TAG, "Installer failed to copy system profile!"); } else { // Disabled as this causes speed-profile compilation during first boot @@ -9788,7 +9798,8 @@ public class PackageManagerService extends IPackageManager.Stub // issue is that we don't have a good way to say "do this only // once". if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), - pkg.applicationInfo.uid, pkg.packageName)) { + pkg.applicationInfo.uid, pkg.packageName, + ArtManager.getProfileName(null))) { Log.e(TAG, "Failed to copy system profile for stub package!"); } else { useProfileForDexopt = true; @@ -9827,13 +9838,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - String pkgCompilerFilter = compilerFilter; + int pkgCompilationReason = compilationReason; if (useProfileForDexopt) { // Use background dexopt mode to try and use the profile. Note that this does not // guarantee usage of the profile. - pkgCompilerFilter = - PackageManagerServiceCompilerMapping.getCompilerFilterForReason( - PackageManagerService.REASON_BACKGROUND_DEXOPT); + pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT; } // checkProfiles is false to avoid merging profiles during boot which @@ -9842,9 +9851,13 @@ public class PackageManagerService extends IPackageManager.Stub // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a // trade-off worth doing to save boot time work. int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0; + if (compilationReason == REASON_FIRST_BOOT) { + // TODO: This doesn't cover the upgrade case, we should check for this too. + dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE; + } int primaryDexOptStaus = performDexOptTraced(new DexoptOptions( pkg.packageName, - pkgCompilerFilter, + pkgCompilationReason, dexoptFlags)); switch (primaryDexOptStaus) { @@ -9944,8 +9957,8 @@ public class PackageManagerService extends IPackageManager.Stub int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) | (force ? DexoptOptions.DEXOPT_FORCE : 0) | (bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0); - return performDexOpt(new DexoptOptions(packageName, targetCompilerFilter, - splitName, flags)); + return performDexOpt(new DexoptOptions(packageName, REASON_UNKNOWN, + targetCompilerFilter, splitName, flags)); } /** @@ -10054,7 +10067,8 @@ public class PackageManagerService extends IPackageManager.Stub final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo); if (!deps.isEmpty()) { DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(), - options.getCompilerFilter(), options.getSplitName(), + options.getCompilationReason(), options.getCompilerFilter(), + options.getSplitName(), options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY); for (PackageParser.Package depPackage : deps) { // TODO: Analyze and investigate if we (should) profile libraries. @@ -10213,14 +10227,7 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mInstallLock) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dump profiles"); - final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); - try { - List<String> allCodePaths = pkg.getAllCodePathsExcludingResourceOnly(); - String codePaths = TextUtils.join(";", allCodePaths); - mInstaller.dumpProfiles(sharedGid, packageName, codePaths); - } catch (InstallerException e) { - Slog.w(TAG, "Failed to dump profiles", e); - } + mArtManagerService.dumpProfiles(pkg); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } @@ -10296,6 +10303,8 @@ public class PackageManagerService extends IPackageManager.Stub for (int i = 0; i < childCount; i++) { clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags); } + + clearAppProfilesLIF(pkg, UserHandle.USER_ALL); } private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) { @@ -10368,18 +10377,10 @@ public class PackageManagerService extends IPackageManager.Stub Slog.wtf(TAG, "Package was null!", new Throwable()); return; } - clearAppProfilesLeafLIF(pkg); + mArtManagerService.clearAppProfiles(pkg); final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; for (int i = 0; i < childCount; i++) { - clearAppProfilesLeafLIF(pkg.childPackages.get(i)); - } - } - - private void clearAppProfilesLeafLIF(PackageParser.Package pkg) { - try { - mInstaller.clearAppProfiles(pkg.packageName); - } catch (InstallerException e) { - Slog.w(TAG, String.valueOf(e)); + mArtManagerService.clearAppProfiles(pkg.childPackages.get(i)); } } @@ -17901,7 +17902,6 @@ public class PackageManagerService extends IPackageManager.Stub clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); - clearAppProfilesLIF(deletedPackage, UserHandle.USER_ALL); try { final PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, @@ -18037,7 +18037,6 @@ public class PackageManagerService extends IPackageManager.Stub // Successfully disabled the old package. Now proceed with re-installation clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); - clearAppProfilesLIF(deletedPackage, UserHandle.USER_ALL); res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, @@ -18463,6 +18462,7 @@ public class PackageManagerService extends IPackageManager.Stub final PackageParser.Package pkg; try { pkg = pp.parsePackage(tmpPackageFile, parseFlags); + DexMetadataHelper.validatePackageDexMetadata(pkg); } catch (PackageParserException e) { res.setError("Failed parse during installPackageLI", e); return; @@ -18837,6 +18837,11 @@ public class PackageManagerService extends IPackageManager.Stub } } + // Prepare the application profiles for the new code paths. + // This needs to be done before invoking dexopt so that any install-time profile + // can be used for optimizations. + mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier())); + // Check whether we need to dexopt the app. // // NOTE: it is IMPORTANT to call dexopt: @@ -18871,7 +18876,8 @@ public class PackageManagerService extends IPackageManager.Stub // Also, don't fail application installs if the dexopt step fails. DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName, REASON_INSTALL, - DexoptOptions.DEXOPT_BOOT_COMPLETE); + DexoptOptions.DEXOPT_BOOT_COMPLETE | + DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE); mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles, null /* instructionSets */, getOrCreateCompilerPackageStats(pkg), @@ -22051,7 +22057,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } clearAppDataLIF(newPkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); - clearAppProfilesLIF(newPkg, UserHandle.USER_ALL); mDexManager.notifyPackageUpdated(newPkg.packageName, newPkg.baseCodePath, newPkg.splitCodePaths); } @@ -24211,6 +24216,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e); } } + // Prepare the application profiles. + mArtManagerService.prepareAppProfiles(pkg, userId); if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) { // TODO: mark this structure as dirty so we persist it! @@ -24907,6 +24914,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); return mInstallerService; } + @Override + public IArtManager getArtManager() { + return mArtManagerService; + } + private boolean userNeedsBadging(int userId) { int index = mUserNeedsBadging.indexOfKey(userId); if (index < 0) { diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java index 19b0d9bc4b90..fce828581c54 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java @@ -123,4 +123,14 @@ public class PackageManagerServiceCompilerMapping { return value; } + + public static String getReasonName(int reason) { + if (reason == PackageManagerService.REASON_UNKNOWN) { + return "unknown"; + } + if (reason < 0 || reason >= REASON_STRINGS.length) { + throw new IllegalArgumentException("reason " + reason + " invalid"); + } + return REASON_STRINGS[reason]; + } } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 806abec6b3eb..3857c96f601d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -42,6 +42,7 @@ import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.VersionedPackage; +import android.content.pm.dex.DexMetadataHelper; import android.content.res.AssetManager; import android.content.res.Resources; import android.net.Uri; @@ -1480,6 +1481,14 @@ class PackageManagerShellCommand extends ShellCommand { session = new PackageInstaller.Session( mInterface.getPackageInstaller().openSession(sessionId)); + // Sanity check that all .dm files match an apk. + // (The installer does not support standalone .dm files and will not process them.) + try { + DexMetadataHelper.validateDexPaths(session.getNames()); + } catch (IllegalStateException | IOException e) { + pw.println("Warning [Could not validate the dex paths: " + e.getMessage() + "]"); + } + final LocalIntentReceiver receiver = new LocalIntentReceiver(); session.commit(receiver.getIntentSender()); diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java new file mode 100644 index 000000000000..e29027288e9b --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.pm.dex; + +import android.Manifest; +import android.annotation.UserIdInt; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.dex.ArtManager; +import android.content.pm.dex.ArtManager.ProfileType; +import android.content.pm.dex.DexMetadataHelper; +import android.os.Binder; +import android.os.Build; +import android.os.Handler; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.content.pm.IPackageManager; +import android.content.pm.dex.ISnapshotRuntimeProfileCallback; +import android.os.SystemProperties; +import android.os.UserHandle; +import android.system.Os; +import android.util.ArrayMap; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.BackgroundThread; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.Preconditions; +import com.android.server.pm.Installer; +import com.android.server.pm.Installer.InstallerException; +import java.io.File; +import java.io.FileNotFoundException; +import libcore.io.IoUtils; +import libcore.util.NonNull; +import libcore.util.Nullable; + +/** + * A system service that provides access to runtime and compiler artifacts. + * + * This service is not accessed by users directly, instead one uses an instance of + * {@link ArtManager}, which can be accessed via {@link PackageManager} as follows: + * <p/> + * {@code context().getPackageManager().getArtManager();} + * <p class="note"> + * Note: Accessing runtime artifacts may require extra permissions. For example querying the + * runtime profiles of apps requires {@link android.Manifest.permission#READ_RUNTIME_PROFILES} + * which is a system-level permission that will not be granted to normal apps. + */ +public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { + private static final String TAG = "ArtManagerService"; + + private static boolean DEBUG = false; + private static boolean DEBUG_IGNORE_PERMISSIONS = false; + + // Package name used to create the profile directory layout when + // taking a snapshot of the boot image profile. + private static final String BOOT_IMAGE_ANDROID_PACKAGE = "android"; + // Profile name used for the boot image profile. + private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof"; + + private final IPackageManager mPackageManager; + private final Object mInstallLock; + @GuardedBy("mInstallLock") + private final Installer mInstaller; + + private final Handler mHandler; + + public ArtManagerService(IPackageManager pm, Installer installer, Object installLock) { + mPackageManager = pm; + mInstaller = installer; + mInstallLock = installLock; + mHandler = new Handler(BackgroundThread.getHandler().getLooper()); + } + + @Override + public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName, + @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback) { + // Sanity checks on the arguments. + Preconditions.checkNotNull(callback); + + boolean bootImageProfile = profileType == ArtManager.PROFILE_BOOT_IMAGE; + if (!bootImageProfile) { + Preconditions.checkStringNotEmpty(codePath); + Preconditions.checkStringNotEmpty(packageName); + } + + // Verify that the caller has the right permissions and that the runtime profiling is + // enabled. The call to isRuntimePermissions will checkReadRuntimeProfilePermission. + if (!isRuntimeProfilingEnabled(profileType)) { + throw new IllegalStateException("Runtime profiling is not enabled for " + profileType); + } + + if (DEBUG) { + Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath); + } + + if (bootImageProfile) { + snapshotBootImageProfile(callback); + } else { + snapshotAppProfile(packageName, codePath, callback); + } + } + + private void snapshotAppProfile(String packageName, String codePath, + ISnapshotRuntimeProfileCallback callback) { + PackageInfo info = null; + try { + // Note that we use the default user 0 to retrieve the package info. + // This doesn't really matter because for user 0 we always get a package back (even if + // it's not installed for the user 0). It is ok because we only care about the code + // paths and not if the package is enabled or not for the user. + + // TODO(calin): consider adding an API to PMS which can retrieve the + // PackageParser.Package. + info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0); + } catch (RemoteException ignored) { + // Should not happen. + } + if (info == null) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_PACKAGE_NOT_FOUND); + return; + } + + boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath); + String splitName = null; + String[] splitCodePaths = info.applicationInfo.getSplitCodePaths(); + if (!pathFound && (splitCodePaths != null)) { + for (int i = splitCodePaths.length - 1; i >= 0; i--) { + if (splitCodePaths[i].equals(codePath)) { + pathFound = true; + splitName = info.applicationInfo.splitNames[i]; + break; + } + } + } + if (!pathFound) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND); + return; + } + + // All good, create the profile snapshot. + int appId = UserHandle.getAppId(info.applicationInfo.uid); + if (appId < 0) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + Slog.wtf(TAG, "AppId is -1 for package: " + packageName); + return; + } + + createProfileSnapshot(packageName, ArtManager.getProfileName(splitName), codePath, + appId, callback); + // Destroy the snapshot, we no longer need it. + destroyProfileSnapshot(packageName, ArtManager.getProfileName(splitName)); + } + + private void createProfileSnapshot(String packageName, String profileName, String classpath, + int appId, ISnapshotRuntimeProfileCallback callback) { + // Ask the installer to snapshot the profile. + synchronized (mInstallLock) { + try { + if (!mInstaller.createProfileSnapshot(appId, packageName, profileName, classpath)) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + return; + } + } catch (InstallerException e) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + return; + } + } + + // Open the snapshot and invoke the callback. + File snapshotProfile = ArtManager.getProfileSnapshotFileForName(packageName, profileName); + + ParcelFileDescriptor fd = null; + try { + fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY); + postSuccess(packageName, fd, callback); + } catch (FileNotFoundException e) { + Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":" + + snapshotProfile, e); + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + } finally { + IoUtils.closeQuietly(fd); + } + } + + private void destroyProfileSnapshot(String packageName, String profileName) { + if (DEBUG) { + Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + profileName); + } + + synchronized (mInstallLock) { + try { + mInstaller.destroyProfileSnapshot(packageName, profileName); + } catch (InstallerException e) { + Slog.e(TAG, "Failed to destroy profile snapshot for " + + packageName + ":" + profileName, e); + } + } + } + + @Override + public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) { + // Verify that the caller has the right permissions. + checkReadRuntimeProfilePermission(); + + switch (profileType) { + case ArtManager.PROFILE_APPS : + return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); + case ArtManager.PROFILE_BOOT_IMAGE: + return (Build.IS_USERDEBUG || Build.IS_ENG) && + SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false) && + SystemProperties.getBoolean("dalvik.vm.profilebootimage", false); + default: + throw new IllegalArgumentException("Invalid profile type:" + profileType); + } + } + + private void snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback) { + // Combine the profiles for boot classpath and system server classpath. + // This avoids having yet another type of profiles and simplifies the processing. + String classpath = String.join(":", Os.getenv("BOOTCLASSPATH"), + Os.getenv("SYSTEMSERVERCLASSPATH")); + + // Create the snapshot. + createProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME, classpath, + /*appId*/ -1, callback); + // Destroy the snapshot, we no longer need it. + destroyProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME); + } + + /** + * Post {@link ISnapshotRuntimeProfileCallback#onError(int)} with the given error message + * on the internal {@code mHandler}. + */ + private void postError(ISnapshotRuntimeProfileCallback callback, String packageName, + int errCode) { + if (DEBUG) { + Slog.d(TAG, "Failed to snapshot profile for " + packageName + " with error: " + + errCode); + } + mHandler.post(() -> { + try { + callback.onError(errCode); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to callback after profile snapshot for " + packageName, e); + } + }); + } + + private void postSuccess(String packageName, ParcelFileDescriptor fd, + ISnapshotRuntimeProfileCallback callback) { + if (DEBUG) { + Slog.d(TAG, "Successfully snapshot profile for " + packageName); + } + mHandler.post(() -> { + try { + callback.onSuccess(fd); + } catch (RemoteException e) { + Slog.w(TAG, + "Failed to call onSuccess after profile snapshot for " + packageName, e); + } + }); + } + + /** + * Verify that the binder calling uid has {@code android.permission.READ_RUNTIME_PROFILE}. + * If not, it throws a {@link SecurityException}. + */ + private void checkReadRuntimeProfilePermission() { + if (DEBUG_IGNORE_PERMISSIONS) { + return; + } + try { + int result = mPackageManager.checkUidPermission( + Manifest.permission.READ_RUNTIME_PROFILES, Binder.getCallingUid()); + if (result != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need " + + Manifest.permission.READ_RUNTIME_PROFILES + + " permission to snapshot profiles."); + } + } catch (RemoteException e) { + // Should not happen. + } + } + + /** + * Prepare the application profiles. + * For all code paths: + * - create the current primary profile to save time at app startup time. + * - copy the profiles from the associated dex metadata file to the reference profile. + */ + public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user) { + final int appId = UserHandle.getAppId(pkg.applicationInfo.uid); + if (user < 0) { + Slog.wtf(TAG, "Invalid user id: " + user); + return; + } + if (appId < 0) { + Slog.wtf(TAG, "Invalid app id: " + appId); + return; + } + try { + ArrayMap<String, String> codePathsProfileNames = getPackageProfileNames(pkg); + for (int i = codePathsProfileNames.size() - 1; i >= 0; i--) { + String codePath = codePathsProfileNames.keyAt(i); + String profileName = codePathsProfileNames.valueAt(i); + File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath)); + String dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath(); + synchronized (mInstaller) { + boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId, + profileName, codePath, dexMetadataPath); + if (!result) { + Slog.e(TAG, "Failed to prepare profile for " + + pkg.packageName + ":" + codePath); + } + } + } + } catch (InstallerException e) { + Slog.e(TAG, "Failed to prepare profile for " + pkg.packageName, e); + } + } + + /** + * Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}. + */ + public void prepareAppProfiles(PackageParser.Package pkg, int[] user) { + for (int i = 0; i < user.length; i++) { + prepareAppProfiles(pkg, user[i]); + } + } + + /** + * Clear the profiles for the given package. + */ + public void clearAppProfiles(PackageParser.Package pkg) { + try { + ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg); + for (int i = packageProfileNames.size() - 1; i >= 0; i--) { + String profileName = packageProfileNames.valueAt(i); + mInstaller.clearAppProfiles(pkg.packageName, profileName); + } + } catch (InstallerException e) { + Slog.w(TAG, String.valueOf(e)); + } + } + + /** + * Dumps the profiles for the given package. + */ + public void dumpProfiles(PackageParser.Package pkg) { + final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + try { + ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg); + for (int i = packageProfileNames.size() - 1; i >= 0; i--) { + String codePath = packageProfileNames.keyAt(i); + String profileName = packageProfileNames.valueAt(i); + synchronized (mInstallLock) { + mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath); + } + } + } catch (InstallerException e) { + Slog.w(TAG, "Failed to dump profiles", e); + } + } + + /** + * Build the profiles names for all the package code paths (excluding resource only paths). + * Return the map [code path -> profile name]. + */ + private ArrayMap<String, String> getPackageProfileNames(PackageParser.Package pkg) { + ArrayMap<String, String> result = new ArrayMap<>(); + if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { + result.put(pkg.baseCodePath, ArtManager.getProfileName(null)); + } + if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { + for (int i = 0; i < pkg.splitCodePaths.length; i++) { + if ((pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { + result.put(pkg.splitCodePaths[i], ArtManager.getProfileName(pkg.splitNames[i])); + } + } + } + return result; + } +} diff --git a/services/core/java/com/android/server/pm/dex/DexLogger.java b/services/core/java/com/android/server/pm/dex/DexLogger.java new file mode 100644 index 000000000000..c7bbf1cbc5c6 --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/DexLogger.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.pm.dex; + +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.os.RemoteException; + +import android.util.ArraySet; +import android.util.ByteStringUtils; +import android.util.EventLog; +import android.util.PackageUtils; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.pm.Installer; +import com.android.server.pm.Installer.InstallerException; + +import java.io.File; +import java.util.Set; + +import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; + +/** + * This class is responsible for logging data about secondary dex files. + * The data logged includes hashes of the name and content of each file. + */ +public class DexLogger implements DexManager.Listener { + private static final String TAG = "DexLogger"; + + // Event log tag & subtag used for SafetyNet logging of dynamic + // code loading (DCL) - see b/63927552. + private static final int SNET_TAG = 0x534e4554; + private static final String DCL_SUBTAG = "dcl"; + + private final IPackageManager mPackageManager; + private final Object mInstallLock; + @GuardedBy("mInstallLock") + private final Installer mInstaller; + + public static DexManager.Listener getListener(IPackageManager pms, + Installer installer, Object installLock) { + return new DexLogger(pms, installer, installLock); + } + + private DexLogger(IPackageManager pms, Installer installer, Object installLock) { + mPackageManager = pms; + mInstaller = installer; + mInstallLock = installLock; + } + + /** + * Compute and log hashes of the name and content of a secondary dex file. + */ + @Override + public void onReconcileSecondaryDexFile(ApplicationInfo appInfo, DexUseInfo dexUseInfo, + String dexPath, int storageFlags) { + int ownerUid = appInfo.uid; + + byte[] hash = null; + synchronized(mInstallLock) { + try { + hash = mInstaller.hashSecondaryDexFile(dexPath, appInfo.packageName, + ownerUid, appInfo.volumeUuid, storageFlags); + } catch (InstallerException e) { + Slog.e(TAG, "Got InstallerException when hashing dex " + dexPath + + " : " + e.getMessage()); + } + } + if (hash == null) { + return; + } + + String dexFileName = new File(dexPath).getName(); + String message = PackageUtils.computeSha256Digest(dexFileName.getBytes()); + // Valid SHA256 will be 256 bits, 32 bytes. + if (hash.length == 32) { + message = message + ' ' + ByteStringUtils.toHexString(hash); + } + + EventLog.writeEvent(SNET_TAG, DCL_SUBTAG, ownerUid, message); + + if (dexUseInfo.isUsedByOtherApps()) { + Set<String> otherPackages = dexUseInfo.getLoadingPackages(); + Set<Integer> otherUids = new ArraySet<>(otherPackages.size()); + for (String otherPackageName : otherPackages) { + try { + int otherUid = mPackageManager.getPackageUid( + otherPackageName, /*flags*/0, dexUseInfo.getOwnerUserId()); + if (otherUid != -1 && otherUid != ownerUid) { + otherUids.add(otherUid); + } + } catch (RemoteException ignore) { + // Can't happen, we're local. + } + } + for (int otherUid : otherUids) { + EventLog.writeEvent(SNET_TAG, DCL_SUBTAG, otherUid, message); + } + } + } +} diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index 62747547f320..3e63fb42f0ef 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -76,6 +76,7 @@ public class DexManager { private final Object mInstallLock; @GuardedBy("mInstallLock") private final Installer mInstaller; + private final Listener mListener; // Possible outcomes of a dex search. private static int DEX_SEARCH_NOT_FOUND = 0; // dex file not found @@ -96,14 +97,24 @@ public class DexManager { */ private final static PackageUseInfo DEFAULT_USE_INFO = new PackageUseInfo(); + public interface Listener { + /** + * Invoked just before the secondary dex file {@code dexPath} for the specified application + * is reconciled. + */ + void onReconcileSecondaryDexFile(ApplicationInfo appInfo, DexUseInfo dexUseInfo, + String dexPath, int storageFlags); + } + public DexManager(IPackageManager pms, PackageDexOptimizer pdo, - Installer installer, Object installLock) { + Installer installer, Object installLock, Listener listener) { mPackageCodeLocationsCache = new HashMap<>(); mPackageDexUsage = new PackageDexUsage(); mPackageManager = pms; mPackageDexOptimizer = pdo; mInstaller = installer; mInstallLock = installLock; + mListener = listener; } /** @@ -389,7 +400,7 @@ public class DexManager { : mPackageDexOptimizer; String packageName = options.getPackageName(); PackageUseInfo useInfo = getPackageUseInfoOrDefault(packageName); - if (useInfo == null || useInfo.getDexUseInfoMap().isEmpty()) { + if (useInfo.getDexUseInfoMap().isEmpty()) { if (DEBUG) { Slog.d(TAG, "No secondary dex use for package:" + packageName); } @@ -433,7 +444,7 @@ public class DexManager { */ public void reconcileSecondaryDexFiles(String packageName) { PackageUseInfo useInfo = getPackageUseInfoOrDefault(packageName); - if (useInfo == null || useInfo.getDexUseInfoMap().isEmpty()) { + if (useInfo.getDexUseInfoMap().isEmpty()) { if (DEBUG) { Slog.d(TAG, "No secondary dex use for package:" + packageName); } @@ -481,12 +492,16 @@ public class DexManager { continue; } + if (mListener != null) { + mListener.onReconcileSecondaryDexFile(info, dexUseInfo, dexPath, flags); + } + boolean dexStillExists = true; synchronized(mInstallLock) { try { String[] isas = dexUseInfo.getLoaderIsas().toArray(new String[0]); dexStillExists = mInstaller.reconcileSecondaryDexFile(dexPath, packageName, - pkg.applicationInfo.uid, isas, pkg.applicationInfo.volumeUuid, flags); + info.uid, isas, info.volumeUuid, flags); } catch (InstallerException e) { Slog.e(TAG, "Got InstallerException when reconciling dex " + dexPath + " : " + e.getMessage()); @@ -534,13 +549,12 @@ public class DexManager { mPackageDexUsage.maybeWriteAsync(); } - // Try to optimize the package according to the install reason. - String compilerFilter = PackageManagerServiceCompilerMapping.getCompilerFilterForReason( - PackageManagerService.REASON_INSTALL); DexUseInfo dexUseInfo = mPackageDexUsage.getPackageUseInfo(searchResult.mOwningPackageName) .getDexUseInfoMap().get(dexPath); - DexoptOptions options = new DexoptOptions(info.packageName, compilerFilter, /*flags*/0); + // Try to optimize the package according to the install reason. + DexoptOptions options = new DexoptOptions(info.packageName, + PackageManagerService.REASON_INSTALL, /*flags*/0); int result = mPackageDexOptimizer.dexOptSecondaryDexPath(info, dexPath, dexUseInfo, options); diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java index 0966770d4897..a7a7686b2a6b 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java +++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java @@ -59,6 +59,10 @@ public final class DexoptOptions { // When set, indicates that dexopt is invoked from the background service. public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9; + // When set, indicates that dexopt is invoked from the install time flow and + // should get the dex metdata file if present. + public static final int DEXOPT_INSTALL_WITH_DEX_METADATA_FILE = 1 << 10; + // The name of package to optimize. private final String mPackageName; @@ -73,15 +77,21 @@ public final class DexoptOptions { // It only applies for primary apk and it's always null if mOnlySecondaryDex is true. private final String mSplitName; + // The reason for invoking dexopt (see PackageManagerService.REASON_* constants). + // A -1 value denotes an unknown reason. + private final int mCompilationReason; + public DexoptOptions(String packageName, String compilerFilter, int flags) { - this(packageName, compilerFilter, /*splitName*/ null, flags); + this(packageName, /*compilationReason*/ -1, compilerFilter, /*splitName*/ null, flags); } - public DexoptOptions(String packageName, int compilerReason, int flags) { - this(packageName, getCompilerFilterForReason(compilerReason), flags); + public DexoptOptions(String packageName, int compilationReason, int flags) { + this(packageName, compilationReason, getCompilerFilterForReason(compilationReason), + /*splitName*/ null, flags); } - public DexoptOptions(String packageName, String compilerFilter, String splitName, int flags) { + public DexoptOptions(String packageName, int compilationReason, String compilerFilter, + String splitName, int flags) { int validityMask = DEXOPT_CHECK_FOR_PROFILES_UPDATES | DEXOPT_FORCE | @@ -90,7 +100,8 @@ public final class DexoptOptions { DEXOPT_ONLY_SHARED_DEX | DEXOPT_DOWNGRADE | DEXOPT_AS_SHARED_LIBRARY | - DEXOPT_IDLE_BACKGROUND_JOB; + DEXOPT_IDLE_BACKGROUND_JOB | + DEXOPT_INSTALL_WITH_DEX_METADATA_FILE; if ((flags & (~validityMask)) != 0) { throw new IllegalArgumentException("Invalid flags : " + Integer.toHexString(flags)); } @@ -99,6 +110,7 @@ public final class DexoptOptions { mCompilerFilter = compilerFilter; mFlags = flags; mSplitName = splitName; + mCompilationReason = compilationReason; } public String getPackageName() { @@ -141,6 +153,10 @@ public final class DexoptOptions { return (mFlags & DEXOPT_IDLE_BACKGROUND_JOB) != 0; } + public boolean isDexoptInstallWithDexMetadata() { + return (mFlags & DEXOPT_INSTALL_WITH_DEX_METADATA_FILE) != 0; + } + public String getSplitName() { return mSplitName; } @@ -148,4 +164,8 @@ public final class DexoptOptions { public int getFlags() { return mFlags; } + + public int getCompilationReason() { + return mCompilationReason; + } } diff --git a/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java b/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java new file mode 100644 index 000000000000..045081679d81 --- /dev/null +++ b/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.updates; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.provider.Telephony; +import android.util.Log; + +public class CarrierIdInstallReceiver extends ConfigUpdateInstallReceiver { + + public CarrierIdInstallReceiver() { + super("/data/misc/carrierid", "carrier_list.pb", "metadata/", "version"); + } + + @Override + protected void postInstall(Context context, Intent intent) { + ContentResolver resolver = context.getContentResolver(); + resolver.update(Uri.withAppendedPath(Telephony.CarrierIdentification.All.CONTENT_URI, + "update_db"), new ContentValues(), null, null); + } +} diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java index bf769ed46bc1..1e334b83d8b0 100644 --- a/services/core/java/com/android/server/webkit/SystemImpl.java +++ b/services/core/java/com/android/server/webkit/SystemImpl.java @@ -304,6 +304,6 @@ public class SystemImpl implements SystemInterface { // flags declaring we want extra info from the package manager for webview providers private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA - | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING - | PackageManager.MATCH_ANY_USER; + | PackageManager.GET_SIGNATURES | PackageManager.GET_SHARED_LIBRARY_FILES + | PackageManager.MATCH_DEBUG_TRIAGED_MISSING | PackageManager.MATCH_ANY_USER; } diff --git a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java new file mode 100644 index 000000000000..6e76b679940b --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java @@ -0,0 +1,189 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; + +import android.support.test.runner.AndroidJUnit4; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Unit tests for {@link WatchdogDiagnostics} + */ +@RunWith(AndroidJUnit4.class) +public class WatchdogDiagnosticsTest { + + private static class TestThread1 extends Thread { + Object lock1; + Object lock2; + volatile boolean inB = false; + + public TestThread1(Object lock1, Object lock2) { + super("TestThread1"); + this.lock1 = lock1; + this.lock2 = lock2; + } + + @Override + public void run() { + a(); + } + + private void a() { + synchronized(lock1) { + b(); + } + } + + private void b() { + inB = true; + synchronized(lock2) { + // Nothing. + } + } + } + + private static class TestThread2 extends Thread { + Object lock1; + Object lock2; + volatile boolean inY = false; + + public TestThread2(Object lock1, Object lock2) { + super("TestThread2"); + this.lock1 = lock1; + this.lock2 = lock2; + } + + @Override + public void run() { + x(); + } + + private void x() { + synchronized(lock1) { + y(); + } + } + + private void y() { + synchronized(lock2) { + inY = true; + try { + lock2.wait(); + } catch (Exception exc) { + throw new RuntimeException(exc); + } + } + } + } + + @Test + public void printAnnotatedStack() throws Exception { + // Preparation. + + Object heldLock1 = new Object(); + Object heldLock2 = 0; + Object waitLock = "123"; + + TestThread1 thread1 = new TestThread1(heldLock1, heldLock2); + TestThread2 thread2 = new TestThread2(heldLock2, waitLock); + + // Start the second thread, ensure it grabs heldLock2. + thread2.start(); + while(!thread2.inY) { + Thread.yield(); + } + + // Start the first thread, ensure it made progress. + thread1.start(); + while(!thread1.inB) { + Thread.yield(); + } + + // Now wait till both are no longer in runnable state. + while (thread1.getState() == Thread.State.RUNNABLE) { + Thread.yield(); + } + while (thread2.getState() == Thread.State.RUNNABLE) { + Thread.yield(); + } + + // Now do the test. + StringWriter stringBuffer = new StringWriter(); + PrintWriter print = new PrintWriter(stringBuffer, true); + + { + WatchdogDiagnostics.printAnnotatedStack(thread1, print); + + String output = stringBuffer.toString(); + String expected = + "TestThread1 annotated stack trace:\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread1.b(" + + "WatchdogDiagnosticsTest.java:59)\n" + + " - waiting to lock <HASH> (a java.lang.Integer)\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread1.a(" + + "WatchdogDiagnosticsTest.java:53)\n" + + " - locked <HASH> (a java.lang.Object)\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread1.run(" + + "WatchdogDiagnosticsTest.java:48)\n"; + assertEquals(expected, filterHashes(output)); + } + + stringBuffer.getBuffer().setLength(0); + + { + WatchdogDiagnostics.printAnnotatedStack(thread2, print); + + String output = stringBuffer.toString(); + String expected = + "TestThread2 annotated stack trace:\n" + + " at java.lang.Object.wait(Native Method)\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread2.y(" + + "WatchdogDiagnosticsTest.java:91)\n" + + " - locked <HASH> (a java.lang.String)\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread2.x(" + + "WatchdogDiagnosticsTest.java:83)\n" + + " - locked <HASH> (a java.lang.Integer)\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread2.run(" + + "WatchdogDiagnosticsTest.java:78)\n"; + assertEquals(expected, filterHashes(output)); + } + + // Let the threads finish. + synchronized (waitLock) { + waitLock.notifyAll(); + } + + thread1.join(); + thread2.join(); + } + + /** + * A filter function that removes hash codes (which will change between tests and cannot be + * controlled.) + * <p> + * Note: leaves "<HASH>" to indicate that something was replaced. + */ + private static String filterHashes(String t) { + return t.replaceAll("<0x[0-9a-f]{8}>", "<HASH>"); + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java index 4db9a30a11ca..36d0c8bec09e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java @@ -17,12 +17,15 @@ package com.android.server.pm.dex; import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.os.Build; import android.os.UserHandle; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import com.android.server.pm.Installer; + import dalvik.system.DelegateLastClassLoader; import dalvik.system.PathClassLoader; import dalvik.system.VMRuntime; @@ -36,8 +39,13 @@ import java.util.List; import java.util.Map; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.quality.Strictness; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -45,6 +53,12 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo; import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; @@ -56,6 +70,12 @@ public class DexManagerTests { private static final String DELEGATE_LAST_CLASS_LOADER_NAME = DelegateLastClassLoader.class.getName(); + @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + @Mock Installer mInstaller; + @Mock IPackageManager mPM; + private final Object mInstallLock = new Object(); + @Mock DexManager.Listener mListener; + private DexManager mDexManager; private TestData mFooUser0; @@ -90,7 +110,8 @@ public class DexManagerTests { mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0, DELEGATE_LAST_CLASS_LOADER_NAME); - mDexManager = new DexManager(null, null, null, null); + mDexManager = new DexManager( + mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock, mListener); // Foo and Bar are available to user0. // Only Bar is available to user1; @@ -440,6 +461,20 @@ public class DexManagerTests { } + @Test + public void testReconcileSecondaryDexFiles_invokesListener() throws Exception { + List<String> fooSecondaries = mFooUser0.getSecondaryDexPathsFromProtectedDirs(); + notifyDexLoad(mFooUser0, fooSecondaries, mUser0); + + when(mPM.getPackageInfo(mFooUser0.getPackageName(), 0, 0)) + .thenReturn(mFooUser0.mPackageInfo); + + mDexManager.reconcileSecondaryDexFiles(mFooUser0.getPackageName()); + + verify(mListener, times(fooSecondaries.size())) + .onReconcileSecondaryDexFile(any(ApplicationInfo.class), + any(DexUseInfo.class), anyString(), anyInt()); + } private void assertSecondaryUse(TestData testData, PackageUseInfo pui, List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId, @@ -492,12 +527,12 @@ public class DexManagerTests { } private PackageUseInfo getPackageUseInfo(TestData testData) { - assertTrue(mDexManager.hasInfoOnPackage(testData.mPackageInfo.packageName)); - return mDexManager.getPackageUseInfoOrDefault(testData.mPackageInfo.packageName); + assertTrue(mDexManager.hasInfoOnPackage(testData.getPackageName())); + return mDexManager.getPackageUseInfoOrDefault(testData.getPackageName()); } private void assertNoUseInfo(TestData testData) { - assertFalse(mDexManager.hasInfoOnPackage(testData.mPackageInfo.packageName)); + assertFalse(mDexManager.hasInfoOnPackage(testData.getPackageName())); } private static PackageInfo getMockPackageInfo(String packageName, int userId) { @@ -555,8 +590,8 @@ public class DexManagerTests { List<String> getSecondaryDexPathsFromProtectedDirs() { List<String> paths = new ArrayList<>(); - paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary6.dex"); - paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary7.dex"); + paths.add(mPackageInfo.applicationInfo.deviceProtectedDataDir + "/secondary6.dex"); + paths.add(mPackageInfo.applicationInfo.credentialProtectedDataDir + "/secondary7.dex"); return paths; } diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java index c2072df75bd8..93064bc4ab92 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java @@ -53,6 +53,7 @@ public class DexoptOptionsTests { assertFalse(opt.isDowngrade()); assertFalse(opt.isForce()); assertFalse(opt.isDexoptIdleBackgroundJob()); + assertFalse(opt.isDexoptInstallWithDexMetadata()); } @Test @@ -65,7 +66,8 @@ public class DexoptOptionsTests { DexoptOptions.DEXOPT_ONLY_SHARED_DEX | DexoptOptions.DEXOPT_DOWNGRADE | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY | - DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB; + DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB | + DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE; DexoptOptions opt = new DexoptOptions(mPackageName, mCompilerFilter, flags); assertEquals(mPackageName, opt.getPackageName()); @@ -79,6 +81,7 @@ public class DexoptOptionsTests { assertTrue(opt.isForce()); assertTrue(opt.isDexoptAsSharedLibrary()); assertTrue(opt.isDexoptIdleBackgroundJob()); + assertTrue(opt.isDexoptInstallWithDexMetadata()); } @Test @@ -115,7 +118,7 @@ public class DexoptOptionsTests { public void testCreateDexoptOptionsSplit() { int flags = DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE; - DexoptOptions opt = new DexoptOptions(mPackageName, mCompilerFilter, mSplitName, flags); + DexoptOptions opt = new DexoptOptions(mPackageName, -1, mCompilerFilter, mSplitName, flags); assertEquals(mPackageName, opt.getPackageName()); assertEquals(mCompilerFilter, opt.getCompilerFilter()); assertEquals(mSplitName, opt.getSplitName()); diff --git a/telecomm/OWNERS b/telecomm/OWNERS new file mode 100644 index 000000000000..a3bcfb2cbcfa --- /dev/null +++ b/telecomm/OWNERS @@ -0,0 +1,6 @@ +set noparent + +tgunn@google.com +breadley@google.com +hallliu@google.com +rgreenwalt@google.com diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 8a4b046516ec..2341f03d2ec5 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -352,8 +352,11 @@ public final class Call { */ public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000; + /** Call supports the deflect feature. */ + public static final int CAPABILITY_SUPPORT_DEFLECT = 0x01000000; + //****************************************************************************************** - // Next CAPABILITY value: 0x01000000 + // Next CAPABILITY value: 0x02000000 //****************************************************************************************** /** @@ -529,6 +532,9 @@ public final class Call { if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) { builder.append(" CAPABILITY_CAN_PULL_CALL"); } + if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) { + builder.append(" CAPABILITY_SUPPORT_DEFLECT"); + } builder.append("]"); return builder.toString(); } @@ -1236,6 +1242,15 @@ public final class Call { } /** + * Instructs this {@link #STATE_RINGING} {@code Call} to deflect. + * + * @param address The address to which the call will be deflected. + */ + public void deflect(Uri address) { + mInCallAdapter.deflectCall(mTelecomCallId, address); + } + + /** * Instructs this {@link #STATE_RINGING} {@code Call} to reject. * * @param rejectWithMessage Whether to reject with a text message. diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index 5fcff18aa5be..024bd303304f 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -29,7 +29,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.Objects; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; @@ -82,7 +81,7 @@ public abstract class Conference extends Conferenceable { private int mConnectionProperties; private String mDisconnectMessage; private long mConnectTimeMillis = CONNECT_TIME_NOT_SPECIFIED; - private long mConnectElapsedTimeMillis = CONNECT_TIME_NOT_SPECIFIED; + private long mConnectionStartElapsedRealTime = CONNECT_TIME_NOT_SPECIFIED; private StatusHints mStatusHints; private Bundle mExtras; private Set<String> mPreviousExtraKeys; @@ -584,30 +583,36 @@ public abstract class Conference extends Conferenceable { } /** - * Sets the connection start time of the {@code Conference}. Should be specified in wall-clock - * time returned by {@link System#currentTimeMillis()}. + * Sets the connection start time of the {@code Conference}. This is used in the call log to + * indicate the date and time when the conference took place. + * <p> + * Should be specified in wall-clock time returned by {@link System#currentTimeMillis()}. * <p> * When setting the connection time, you should always set the connection elapsed time via - * {@link #setConnectionElapsedTime(long)}. + * {@link #setConnectionStartElapsedRealTime(long)} to ensure the duration is reflected. * - * @param connectionTimeMillis The connection time, in milliseconds. + * @param connectionTimeMillis The connection time, in milliseconds, as returned by + * {@link System#currentTimeMillis()}. */ public final void setConnectionTime(long connectionTimeMillis) { mConnectTimeMillis = connectionTimeMillis; } /** - * Sets the elapsed time since system boot when the {@link Conference} was connected. - * This is used to determine the duration of the {@link Conference}. + * Sets the start time of the {@link Conference} which is the basis for the determining the + * duration of the {@link Conference}. + * <p> + * You should use a value returned by {@link SystemClock#elapsedRealtime()} to ensure that time + * zone changes do not impact the conference duration. * <p> - * When setting the connection elapsed time, you should always set the connection time via + * When setting this, you should also set the connection time via * {@link #setConnectionTime(long)}. * - * @param connectionElapsedTime The connection time, as measured by + * @param connectionStartElapsedRealTime The connection time, as measured by * {@link SystemClock#elapsedRealtime()}. */ - public final void setConnectionElapsedTime(long connectionElapsedTime) { - mConnectElapsedTimeMillis = connectionElapsedTime; + public final void setConnectionStartElapsedRealTime(long connectionStartElapsedRealTime) { + mConnectionStartElapsedRealTime = connectionStartElapsedRealTime; } /** @@ -642,8 +647,8 @@ public abstract class Conference extends Conferenceable { * @return The elapsed time at which the {@link Conference} was connected. * @hide */ - public final long getConnectElapsedTime() { - return mConnectElapsedTimeMillis; + public final long getConnectionStartElapsedRealTime() { + return mConnectionStartElapsedRealTime; } /** diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 8150efa72571..50c08030719d 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -23,7 +23,6 @@ import com.android.internal.telecom.IVideoProvider; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.TestApi; import android.app.Notification; import android.bluetooth.BluetoothDevice; import android.content.Intent; @@ -328,8 +327,11 @@ public abstract class Connection extends Conferenceable { */ public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000; + /** Call supports the deflect feature. */ + public static final int CAPABILITY_SUPPORT_DEFLECT = 0x02000000; + //********************************************************************************************** - // Next CAPABILITY value: 0x02000000 + // Next CAPABILITY value: 0x04000000 //********************************************************************************************** /** @@ -397,9 +399,7 @@ public abstract class Connection extends Conferenceable { /** * Set by the framework to indicate that a connection has an active RTT session associated with * it. - * @hide */ - @TestApi public static final int PROPERTY_IS_RTT = 1 << 8; /** @@ -729,6 +729,9 @@ public abstract class Connection extends Conferenceable { if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) { builder.append(isLong ? " CAPABILITY_CAN_PULL_CALL" : " pull"); } + if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) { + builder.append(isLong ? " CAPABILITY_SUPPORT_DEFLECT" : " sup_def"); + } builder.append("]"); return builder.toString(); @@ -790,6 +793,10 @@ public abstract class Connection extends Conferenceable { builder.append(isLong ? " PROPERTY_HAS_CDMA_VOICE_PRIVACY" : " priv"); } + if (can(properties, PROPERTY_IS_RTT)) { + builder.append(isLong ? " PROPERTY_IS_RTT" : " rtt"); + } + builder.append("]"); return builder.toString(); } @@ -837,9 +844,7 @@ public abstract class Connection extends Conferenceable { /** * Provides methods to read and write RTT data to/from the in-call app. - * @hide */ - @TestApi public static final class RttTextStream { private static final int READ_BUFFER_SIZE = 1000; private final InputStreamReader mPipeFromInCall; @@ -2292,7 +2297,7 @@ public abstract class Connection extends Conferenceable { * * @hide */ - public final void setConnectElapsedTimeMillis(long connectElapsedTimeMillis) { + public final void setConnectionStartElapsedRealTime(long connectElapsedTimeMillis) { mConnectElapsedTimeMillis = connectElapsedTimeMillis; } @@ -2612,10 +2617,8 @@ public abstract class Connection extends Conferenceable { /** * Informs listeners that a previously requested RTT session via * {@link ConnectionRequest#isRequestingRtt()} or - * {@link #onStartRtt(ParcelFileDescriptor, ParcelFileDescriptor)} has succeeded. - * @hide + * {@link #onStartRtt(RttTextStream)} has succeeded. */ - @TestApi public final void sendRttInitiationSuccess() { setRttProperty(); mListeners.forEach((l) -> l.onRttInitiationSuccess(Connection.this)); @@ -2623,14 +2626,11 @@ public abstract class Connection extends Conferenceable { /** * Informs listeners that a previously requested RTT session via - * {@link ConnectionRequest#isRequestingRtt()} or - * {@link #onStartRtt(ParcelFileDescriptor, ParcelFileDescriptor)} + * {@link ConnectionRequest#isRequestingRtt()} or {@link #onStartRtt(RttTextStream)} * has failed. * @param reason One of the reason codes defined in {@link RttModifyStatus}, with the * exception of {@link RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}. - * @hide */ - @TestApi public final void sendRttInitiationFailure(int reason) { unsetRttProperty(); mListeners.forEach((l) -> l.onRttInitiationFailure(Connection.this, reason)); @@ -2639,19 +2639,16 @@ public abstract class Connection extends Conferenceable { /** * Informs listeners that a currently active RTT session has been terminated by the remote * side of the coll. - * @hide */ - @TestApi public final void sendRttSessionRemotelyTerminated() { + unsetRttProperty(); mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this)); } /** * Informs listeners that the remote side of the call has requested an upgrade to include an * RTT session in the call. - * @hide */ - @TestApi public final void sendRemoteRttRequest() { mListeners.forEach((l) -> l.onRemoteRttRequest(Connection.this)); } @@ -2731,7 +2728,20 @@ public abstract class Connection extends Conferenceable { /** * Notifies this Connection, which is in {@link #STATE_RINGING}, of * a request to accept. - * + * <p> + * For managed {@link ConnectionService}s, this will be called when the user answers a call via + * the default dialer's {@link InCallService}. + * <p> + * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the + * Telecom framework may request that the call is answered in the following circumstances: + * <ul> + * <li>The user chooses to answer an incoming call via a Bluetooth device.</li> + * <li>A car mode {@link InCallService} is in use which has declared + * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest. Such an + * {@link InCallService} will be able to see calls from self-managed + * {@link ConnectionService}s, and will be able to display an incoming call UI on their + * behalf.</li> + * </ul> * @param videoState The video state in which to answer the connection. */ public void onAnswer(int videoState) {} @@ -2739,6 +2749,20 @@ public abstract class Connection extends Conferenceable { /** * Notifies this Connection, which is in {@link #STATE_RINGING}, of * a request to accept. + * <p> + * For managed {@link ConnectionService}s, this will be called when the user answers a call via + * the default dialer's {@link InCallService}. + * <p> + * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the + * Telecom framework may request that the call is answered in the following circumstances: + * <ul> + * <li>The user chooses to answer an incoming call via a Bluetooth device.</li> + * <li>A car mode {@link InCallService} is in use which has declared + * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest. Such an + * {@link InCallService} will be able to see calls from self-managed + * {@link ConnectionService}s, and will be able to display an incoming call UI on their + * behalf.</li> + * </ul> */ public void onAnswer() { onAnswer(VideoProfile.STATE_AUDIO_ONLY); @@ -2746,7 +2770,27 @@ public abstract class Connection extends Conferenceable { /** * Notifies this Connection, which is in {@link #STATE_RINGING}, of + * a request to deflect. + */ + public void onDeflect(Uri address) {} + + /** + * Notifies this Connection, which is in {@link #STATE_RINGING}, of * a request to reject. + * <p> + * For managed {@link ConnectionService}s, this will be called when the user rejects a call via + * the default dialer's {@link InCallService}. + * <p> + * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the + * Telecom framework may request that the call is rejected in the following circumstances: + * <ul> + * <li>The user chooses to reject an incoming call via a Bluetooth device.</li> + * <li>A car mode {@link InCallService} is in use which has declared + * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest. Such an + * {@link InCallService} will be able to see calls from self-managed + * {@link ConnectionService}s, and will be able to display an incoming call UI on their + * behalf.</li> + * </ul> */ public void onReject() {} @@ -2829,9 +2873,10 @@ public abstract class Connection extends Conferenceable { * should show its own incoming call user interface. * <p> * Where there are ongoing calls in other self-managed {@link ConnectionService}s, or in a - * regular {@link ConnectionService}, the Telecom framework will display its own incoming call - * user interface to allow the user to choose whether to answer the new incoming call and - * disconnect other ongoing calls, or to reject the new incoming call. + * regular {@link ConnectionService}, and it is not possible to hold these other calls, the + * Telecom framework will display its own incoming call user interface to allow the user to + * choose whether to answer the new incoming call and disconnect other ongoing calls, or to + * reject the new incoming call. * <p> * You should trigger the display of the incoming call user interface for your application by * showing a {@link Notification} with a full-screen {@link Intent} specified. @@ -2877,17 +2922,13 @@ public abstract class Connection extends Conferenceable { * request, respectively. * @param rttTextStream The object that should be used to send text to or receive text from * the in-call app. - * @hide */ - @TestApi public void onStartRtt(@NonNull RttTextStream rttTextStream) {} /** * Notifies this {@link Connection} that it should terminate any existing RTT communication * channel. No response to Telecom is needed for this method. - * @hide */ - @TestApi public void onStopRtt() {} /** @@ -2895,11 +2936,9 @@ public abstract class Connection extends Conferenceable { * request sent via {@link #sendRemoteRttRequest}. Acceptance of the request is * indicated by the supplied {@link RttTextStream} being non-null, and rejection is * indicated by {@code rttTextStream} being {@code null} - * @hide * @param rttTextStream The object that should be used to send text to or receive text from * the in-call app. */ - @TestApi public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {} /** diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java index e169e5f80741..658b4734b0b5 100644 --- a/telecomm/java/android/telecom/ConnectionRequest.java +++ b/telecomm/java/android/telecom/ConnectionRequest.java @@ -16,7 +16,6 @@ package android.telecom; -import android.annotation.TestApi; import android.net.Uri; import android.os.Bundle; import android.os.Parcel; @@ -310,9 +309,7 @@ public final class ConnectionRequest implements Parcelable { * send and receive RTT text to/from the in-call app. * @return An instance of {@link android.telecom.Connection.RttTextStream}, or {@code null} * if this connection request is not requesting an RTT session upon connection establishment. - * @hide */ - @TestApi public Connection.RttTextStream getRttTextStream() { if (isRequestingRtt()) { return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall); @@ -324,9 +321,7 @@ public final class ConnectionRequest implements Parcelable { /** * Convenience method for determining whether the ConnectionRequest is requesting an RTT session * @return {@code true} if RTT is requested, {@code false} otherwise. - * @hide */ - @TestApi public boolean isRequestingRtt() { return mRttPipeFromInCall != null && mRttPipeToInCall != null; } diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 990b0b4eefee..46d6b4201497 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -21,7 +21,6 @@ import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -124,6 +123,7 @@ public abstract class ConnectionService extends Service { private static final String SESSION_ABORT = "CS.ab"; private static final String SESSION_ANSWER = "CS.an"; private static final String SESSION_ANSWER_VIDEO = "CS.anV"; + private static final String SESSION_DEFLECT = "CS.def"; private static final String SESSION_REJECT = "CS.r"; private static final String SESSION_REJECT_MESSAGE = "CS.rWM"; private static final String SESSION_SILENCE = "CS.s"; @@ -181,6 +181,7 @@ public abstract class ConnectionService extends Service { private static final int MSG_CONNECTION_SERVICE_FOCUS_GAINED = 31; private static final int MSG_HANDOVER_FAILED = 32; private static final int MSG_HANDOVER_COMPLETE = 33; + private static final int MSG_DEFLECT = 34; private static Connection sNullConnection; @@ -353,6 +354,20 @@ public abstract class ConnectionService extends Service { } @Override + public void deflect(String callId, Uri address, Session.Info sessionInfo) { + Log.startSession(sessionInfo, SESSION_DEFLECT); + try { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = callId; + args.arg2 = address; + args.arg3 = Log.createSubsession(); + mHandler.obtainMessage(MSG_DEFLECT, args).sendToTarget(); + } finally { + Log.endSession(); + } + } + + @Override public void reject(String callId, Session.Info sessionInfo) { Log.startSession(sessionInfo, SESSION_REJECT); try { @@ -847,6 +862,17 @@ public abstract class ConnectionService extends Service { } break; } + case MSG_DEFLECT: { + SomeArgs args = (SomeArgs) msg.obj; + Log.continueSession((Session) args.arg3, SESSION_HANDLER + SESSION_DEFLECT); + try { + deflect((String) args.arg1, (Uri) args.arg2); + } finally { + args.recycle(); + Log.endSession(); + } + break; + } case MSG_REJECT: { SomeArgs args = (SomeArgs) msg.obj; Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT); @@ -1605,6 +1631,11 @@ public abstract class ConnectionService extends Service { findConnectionForAction(callId, "answer").onAnswer(); } + private void deflect(String callId, Uri address) { + Log.d(this, "deflect %s", callId); + findConnectionForAction(callId, "deflect").onDeflect(address); + } + private void reject(String callId) { Log.d(this, "reject %s", callId); findConnectionForAction(callId, "reject").onReject(); @@ -1975,7 +2006,7 @@ public abstract class ConnectionService extends Service { null : conference.getVideoProvider().getInterface(), conference.getVideoState(), conference.getConnectTimeMillis(), - conference.getConnectElapsedTime(), + conference.getConnectionStartElapsedRealTime(), conference.getStatusHints(), conference.getExtras()); diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java index 658685fe2907..8678e33f68b6 100644 --- a/telecomm/java/android/telecom/InCallAdapter.java +++ b/telecomm/java/android/telecom/InCallAdapter.java @@ -16,6 +16,7 @@ package android.telecom; +import android.net.Uri; import android.bluetooth.BluetoothDevice; import android.os.Bundle; import android.os.RemoteException; @@ -61,6 +62,19 @@ public final class InCallAdapter { } /** + * Instructs Telecom to deflect the specified call. + * + * @param callId The identifier of the call to deflect. + * @param address The address to deflect. + */ + public void deflectCall(String callId, Uri address) { + try { + mAdapter.deflectCall(callId, address); + } catch (RemoteException e) { + } + } + + /** * Instructs Telecom to reject the specified call. * * @param callId The identifier of the call to reject. diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java index fcf04c9a7eef..af65c65a48b7 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -60,6 +60,26 @@ import java.util.List; * </service> * } * </pre> + * <p> + * In addition to implementing the {@link InCallService} API, you must also declare an activity in + * your manifest which handles the {@link Intent#ACTION_DIAL} intent. The example below illustrates + * how this is done: + * <pre> + * {@code + * <activity android:name="your.package.YourDialerActivity" + * android:label="@string/yourDialerActivityLabel"> + * <intent-filter> + * <action android:name="android.intent.action.DIAL" /> + * <category android:name="android.intent.category.DEFAULT" /> + * </intent-filter> + * </activity> + * } + * </pre> + * <p> + * When a user installs your application and runs it for the first time, you should prompt the user + * to see if they would like your application to be the new default phone app. See the + * {@link TelecomManager#ACTION_CHANGE_DEFAULT_DIALER} intent documentation for more information on + * how to do this. */ public abstract class InCallService extends Service { diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 7e897453ab59..c848f77c2c0e 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -1301,7 +1301,7 @@ public class TelecomManager { public boolean endCall() { try { if (isServiceConnected()) { - return getTelecomService().endCall(); + return getTelecomService().endCall(mContext.getPackageName()); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelecomService#endCall", e); diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl index 3dbc8ddc340f..04f057d96ef2 100644 --- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl +++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl @@ -16,6 +16,7 @@ package com.android.internal.telecom; +import android.net.Uri; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.telecom.CallAudioState; @@ -58,6 +59,8 @@ oneway interface IConnectionService { void answer(String callId, in Session.Info sessionInfo); + void deflect(String callId, in Uri address, in Session.Info sessionInfo); + void reject(String callId, in Session.Info sessionInfo); void rejectWithMessage(String callId, String message, in Session.Info sessionInfo); diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl index 87ccd3ed4369..57df5c1e548e 100644 --- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl @@ -16,6 +16,7 @@ package com.android.internal.telecom; +import android.net.Uri; import android.os.Bundle; import android.telecom.PhoneAccountHandle; @@ -29,6 +30,8 @@ import android.telecom.PhoneAccountHandle; oneway interface IInCallAdapter { void answerCall(String callId, int videoState); + void deflectCall(String callId, in Uri address); + void rejectCall(String callId, boolean rejectWithMessage, String textMessage); void disconnectCall(String callId); diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index 3460754ff9eb..b4e7d56bc642 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -187,7 +187,7 @@ interface ITelecomService { /** * @see TelecomServiceImpl#endCall */ - boolean endCall(); + boolean endCall(String callingPackage); /** * @see TelecomServiceImpl#acceptRingingCall diff --git a/telephony/OWNERS b/telephony/OWNERS new file mode 100644 index 000000000000..6f67bc25f879 --- /dev/null +++ b/telephony/OWNERS @@ -0,0 +1,14 @@ +set noparent + +tgunn@google.com +breadley@google.com +hallliu@google.com +rgreenwalt@google.com +mpq@google.com +amitmahajan@google.com +fionaxu@google.com +jackyu@google.com +jminjie@google.com +satk@google.com +shuoq@google.com +refuhoo@google.com diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 78a0ec27623b..de75ac491f8d 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1370,6 +1370,12 @@ public class CarrierConfigManager { */ public static final String KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL = "allow_hold_in_ims_call"; + /** + * Flag indicating whether the carrier supports call deflection for an incoming IMS call. + * @hide + */ + public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = + "carrier_allow_deflect_ims_call_bool"; /** * Flag indicating whether the carrier always wants to play an "on-hold" tone when a call has @@ -1800,12 +1806,29 @@ public class CarrierConfigManager { public static final String KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY = "lte_rsrp_thresholds_int_array"; + /** + * Decides when clients try to bind to iwlan network service, which package name will + * the binding intent go to. + * @hide + */ + public static final String KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING + = "carrier_network_service_wlan_package_override_string"; + + /** + * Decides when clients try to bind to wwan (cellular) network service, which package name will + * the binding intent go to. + * @hide + */ + public static final String KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING + = "carrier_network_service_wwan_package_override_string"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; static { sDefaults = new PersistableBundle(); sDefaults.putBoolean(KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL, true); + sDefaults.putBoolean(KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL, false); sDefaults.putBoolean(KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL, false); sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true); sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL, false); @@ -1832,13 +1855,15 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false); - sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true); + sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true); sDefaults.putBoolean(KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL, true); sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, ""); sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, ""); + sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, ""); + sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, ""); sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING, ""); sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING, ""); sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING, ""); diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java index f009fb145fc2..7e86966e2c1b 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -172,7 +172,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P } /** - * Get the timing advance value for LTE, as a value between 0..63. + * Get the timing advance value for LTE, as a value in range of 0..1282. * Integer.MAX_VALUE is reported when there is no active RRC * connection. Refer to 3GPP 36.213 Sec 4.2.3 * @return the LTE timing advance, if available. diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java deleted file mode 100644 index b362df9ff677..000000000000 --- a/telephony/java/android/telephony/LocationAccessPolicy.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package android.telephony; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.UserIdInt; -import android.app.ActivityManager; -import android.app.AppOpsManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.UserInfo; -import android.location.LocationManager; -import android.os.Binder; -import android.os.Build; -import android.os.Process; -import android.os.Trace; -import android.os.UserHandle; -import android.os.UserManager; -import android.provider.Settings; -import android.util.SparseBooleanArray; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Helper for performing location access checks. - * @hide - */ -public final class LocationAccessPolicy { - /** - * API to determine if the caller has permissions to get cell location. - * - * @param pkgName Package name of the application requesting access - * @param uid The uid of the package - * @param pid The pid of the package - * @return boolean true or false if permissions is granted - */ - public static boolean canAccessCellLocation(@NonNull Context context, @NonNull String pkgName, - int uid, int pid) throws SecurityException { - Trace.beginSection("TelephonyLocationCheck"); - try { - // Always allow the phone process to access location. This avoid breaking legacy code - // that rely on public-facing APIs to access cell location, and it doesn't create a - // info leak risk because the cell location is stored in the phone process anyway. - if (uid == Process.PHONE_UID) { - return true; - } - - // We always require the location permission and also require the - // location mode to be on for non-legacy apps. Legacy apps are - // required to be in the foreground to at least mitigate the case - // where a legacy app the user is not using tracks their location. - // Granting ACCESS_FINE_LOCATION to an app automatically grants it - // ACCESS_COARSE_LOCATION. - - if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, pid, uid) == - PackageManager.PERMISSION_DENIED) { - return false; - } - final int opCode = AppOpsManager.permissionToOpCode( - Manifest.permission.ACCESS_COARSE_LOCATION); - if (opCode != AppOpsManager.OP_NONE && context.getSystemService(AppOpsManager.class) - .noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) { - return false; - } - if (!isLocationModeEnabled(context, UserHandle.getUserId(uid)) - && !isLegacyForeground(context, pkgName, uid)) { - return false; - } - // If the user or profile is current, permission is granted. - // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission. - return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context); - } finally { - Trace.endSection(); - } - } - - private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) { - int locationMode = Settings.Secure.getIntForUser(context.getContentResolver(), - Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, userId); - return locationMode != Settings.Secure.LOCATION_MODE_OFF - && locationMode != Settings.Secure.LOCATION_MODE_SENSORS_ONLY; - } - - private static boolean isLegacyForeground(@NonNull Context context, @NonNull String pkgName, - int uid) { - long token = Binder.clearCallingIdentity(); - try { - return isLegacyVersion(context, pkgName) && isForegroundApp(context, uid); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private static boolean isLegacyVersion(@NonNull Context context, @NonNull String pkgName) { - try { - if (context.getPackageManager().getApplicationInfo(pkgName, 0) - .targetSdkVersion <= Build.VERSION_CODES.O) { - return true; - } - } catch (PackageManager.NameNotFoundException e) { - // In case of exception, assume known app (more strict checking) - // Note: This case will never happen since checkPackage is - // called to verify validity before checking app's version. - } - return false; - } - - private static boolean isForegroundApp(@NonNull Context context, int uid) { - final ActivityManager am = context.getSystemService(ActivityManager.class); - return am.getUidImportance(uid) <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; - } - - private static boolean checkInteractAcrossUsersFull(@NonNull Context context) { - return context.checkCallingOrSelfPermission( - android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) - == PackageManager.PERMISSION_GRANTED; - } - - private static boolean isCurrentProfile(@NonNull Context context, int uid) { - long token = Binder.clearCallingIdentity(); - try { - final int currentUser = ActivityManager.getCurrentUser(); - final int callingUserId = UserHandle.getUserId(uid); - if (callingUserId == currentUser) { - return true; - } else { - List<UserInfo> userProfiles = context.getSystemService( - UserManager.class).getProfiles(currentUser); - for (UserInfo user : userProfiles) { - if (user.id == callingUserId) { - return true; - } - } - } - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } -} diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java index 4f137bea69f7..bba779d0c175 100644 --- a/telephony/java/android/telephony/NetworkRegistrationState.java +++ b/telephony/java/android/telephony/NetworkRegistrationState.java @@ -298,9 +298,9 @@ public class NetworkRegistrationState implements Parcelable { && mEmergencyOnly == other.mEmergencyOnly && (mAvailableServices == other.mAvailableServices || Arrays.equals(mAvailableServices, other.mAvailableServices)) - && mCellIdentity == other.mCellIdentity - && mVoiceSpecificStates == other.mVoiceSpecificStates - && mDataSpecificStates == other.mDataSpecificStates; + && equals(mCellIdentity, other.mCellIdentity) + && equals(mVoiceSpecificStates, other.mVoiceSpecificStates) + && equals(mDataSpecificStates, other.mDataSpecificStates); } @Override @@ -329,4 +329,14 @@ public class NetworkRegistrationState implements Parcelable { return new NetworkRegistrationState[size]; } }; + + private static boolean equals(Object o1, Object o2) { + if (o1 == o2) { + return true; + } else if (o1 == null) { + return false; + } else { + return o1.equals(o2); + } + } } diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java index 94921de6829b..35682a74744e 100644 --- a/telephony/java/android/telephony/NetworkService.java +++ b/telephony/java/android/telephony/NetworkService.java @@ -28,6 +28,8 @@ import android.os.Message; import android.os.RemoteException; import android.util.SparseArray; +import com.android.internal.annotations.VisibleForTesting; + import java.util.ArrayList; import java.util.List; @@ -38,7 +40,7 @@ import java.util.List; * follow the following format: * ... * <service android:name=".xxxNetworkService" - * android:permission="android.permission.BIND_NETWORK_SERVICE" > + * android:permission="android.permission.BIND_TELEPHONY_NETWORK_SERVICE" > * <intent-filter> * <action android:name="android.telephony.NetworkService" /> * </intent-filter> @@ -68,7 +70,11 @@ public abstract class NetworkService extends Service { private final SparseArray<NetworkServiceProvider> mServiceMap = new SparseArray<>(); - private final INetworkServiceWrapper mBinder = new INetworkServiceWrapper(); + /** + * @hide + */ + @VisibleForTesting + public final INetworkServiceWrapper mBinder = new INetworkServiceWrapper(); /** * The abstract class of the actual network service implementation. The network service provider diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 1176491907ce..ec348dfcc047 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -94,47 +94,6 @@ public class ServiceState implements Parcelable { */ public static final int DUPLEX_MODE_TDD = 2; - /** - * RIL level registration state values from ril.h - * ((const char **)response)[0] is registration state 0-6, - * 0 - Not registered, MT is not currently searching - * a new operator to register - * 1 - Registered, home network - * 2 - Not registered, but MT is currently searching - * a new operator to register - * 3 - Registration denied - * 4 - Unknown - * 5 - Registered, roaming - * 10 - Same as 0, but indicates that emergency calls - * are enabled. - * 12 - Same as 2, but indicates that emergency calls - * are enabled. - * 13 - Same as 3, but indicates that emergency calls - * are enabled. - * 14 - Same as 4, but indicates that emergency calls - * are enabled. - * @hide - */ - public static final int RIL_REG_STATE_NOT_REG = 0; - /** @hide */ - public static final int RIL_REG_STATE_HOME = 1; - /** @hide */ - public static final int RIL_REG_STATE_SEARCHING = 2; - /** @hide */ - public static final int RIL_REG_STATE_DENIED = 3; - /** @hide */ - public static final int RIL_REG_STATE_UNKNOWN = 4; - /** @hide */ - public static final int RIL_REG_STATE_ROAMING = 5; - /** @hide */ - public static final int RIL_REG_STATE_NOT_REG_EMERGENCY_CALL_ENABLED = 10; - /** @hide */ - public static final int RIL_REG_STATE_SEARCHING_EMERGENCY_CALL_ENABLED = 12; - /** @hide */ - public static final int RIL_REG_STATE_DENIED_EMERGENCY_CALL_ENABLED = 13; - /** @hide */ - public static final int RIL_REG_STATE_UNKNOWN_EMERGENCY_CALL_ENABLED = 14; - /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "RIL_RADIO_TECHNOLOGY_" }, @@ -233,22 +192,6 @@ public class ServiceState implements Parcelable { | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_B - 1)) | (1 << (RIL_RADIO_TECHNOLOGY_EHRPD - 1)); - /** - * Available registration states for GSM, UMTS and CDMA. - */ - /** @hide */ - public static final int REGISTRATION_STATE_NOT_REGISTERED_AND_NOT_SEARCHING = 0; - /** @hide */ - public static final int REGISTRATION_STATE_HOME_NETWORK = 1; - /** @hide */ - public static final int REGISTRATION_STATE_NOT_REGISTERED_AND_SEARCHING = 2; - /** @hide */ - public static final int REGISTRATION_STATE_REGISTRATION_DENIED = 3; - /** @hide */ - public static final int REGISTRATION_STATE_UNKNOWN = 4; - /** @hide */ - public static final int REGISTRATION_STATE_ROAMING = 5; - private int mVoiceRegState = STATE_OUT_OF_SERVICE; private int mDataRegState = STATE_OUT_OF_SERVICE; @@ -1373,6 +1316,51 @@ public class ServiceState implements Parcelable { } /** @hide */ + public static int networkTypeToRilRadioTechnology(int networkType) { + switch(networkType) { + case TelephonyManager.NETWORK_TYPE_GPRS: + return ServiceState.RIL_RADIO_TECHNOLOGY_GPRS; + case TelephonyManager.NETWORK_TYPE_EDGE: + return ServiceState.RIL_RADIO_TECHNOLOGY_EDGE; + case TelephonyManager.NETWORK_TYPE_UMTS: + return ServiceState.RIL_RADIO_TECHNOLOGY_UMTS; + case TelephonyManager.NETWORK_TYPE_HSDPA: + return ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA; + case TelephonyManager.NETWORK_TYPE_HSUPA: + return ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA; + case TelephonyManager.NETWORK_TYPE_HSPA: + return ServiceState.RIL_RADIO_TECHNOLOGY_HSPA; + case TelephonyManager.NETWORK_TYPE_CDMA: + return ServiceState.RIL_RADIO_TECHNOLOGY_IS95A; + case TelephonyManager.NETWORK_TYPE_1xRTT: + return ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT; + case TelephonyManager.NETWORK_TYPE_EVDO_0: + return ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0; + case TelephonyManager.NETWORK_TYPE_EVDO_A: + return ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A; + case TelephonyManager.NETWORK_TYPE_EVDO_B: + return ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B; + case TelephonyManager.NETWORK_TYPE_EHRPD: + return ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD; + case TelephonyManager.NETWORK_TYPE_LTE: + return ServiceState.RIL_RADIO_TECHNOLOGY_LTE; + case TelephonyManager.NETWORK_TYPE_HSPAP: + return ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP; + case TelephonyManager.NETWORK_TYPE_GSM: + return ServiceState.RIL_RADIO_TECHNOLOGY_GSM; + case TelephonyManager.NETWORK_TYPE_TD_SCDMA: + return ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA; + case TelephonyManager.NETWORK_TYPE_IWLAN: + return ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN; + case TelephonyManager.NETWORK_TYPE_LTE_CA: + return ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA; + default: + return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; + } + } + + + /** @hide */ public int getDataNetworkType() { return rilRadioTechnologyToNetworkType(mRilDataRadioTechnology); } @@ -1538,7 +1526,9 @@ public class ServiceState implements Parcelable { */ @SystemApi public List<NetworkRegistrationState> getNetworkRegistrationStates() { - return mNetworkRegistrationStates; + synchronized (mNetworkRegistrationStates) { + return new ArrayList<>(mNetworkRegistrationStates); + } } /** @@ -1551,11 +1541,15 @@ public class ServiceState implements Parcelable { @SystemApi public List<NetworkRegistrationState> getNetworkRegistrationStates(int transportType) { List<NetworkRegistrationState> list = new ArrayList<>(); - for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) { - if (networkRegistrationState.getTransportType() == transportType) { - list.add(networkRegistrationState); + + synchronized (mNetworkRegistrationStates) { + for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) { + if (networkRegistrationState.getTransportType() == transportType) { + list.add(networkRegistrationState); + } } } + return list; } @@ -1569,12 +1563,36 @@ public class ServiceState implements Parcelable { */ @SystemApi public NetworkRegistrationState getNetworkRegistrationStates(int transportType, int domain) { - for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) { - if (networkRegistrationState.getTransportType() == transportType - && networkRegistrationState.getDomain() == domain) { - return networkRegistrationState; + synchronized (mNetworkRegistrationStates) { + for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) { + if (networkRegistrationState.getTransportType() == transportType + && networkRegistrationState.getDomain() == domain) { + return networkRegistrationState; + } } } + return null; } + + /** + * @hide + */ + public void addNetworkRegistrationState(NetworkRegistrationState regState) { + if (regState == null) return; + + synchronized (mNetworkRegistrationStates) { + for (int i = 0; i < mNetworkRegistrationStates.size(); i++) { + NetworkRegistrationState curRegState = mNetworkRegistrationStates.get(i); + if (curRegState.getTransportType() == regState.getTransportType() + && curRegState.getDomain() == regState.getDomain()) { + mNetworkRegistrationStates.remove(i); + break; + } + } + + mNetworkRegistrationStates.add(regState); + } + } + } diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 38408fe3d0fd..77413d9c730d 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -34,6 +35,8 @@ import android.os.Parcelable; import android.util.DisplayMetrics; import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; /** * A Parcelable class for Subscription Information. @@ -332,12 +335,7 @@ public class SubscriptionInfo implements Parcelable { return this.mCountryIso; } - /** - * @return whether the subscription is an embedded one. - * @hide - * - * TODO(b/35851809): Make this public. - */ + /** @return whether the subscription is an embedded one. */ public boolean isEmbedded() { return this.mIsEmbedded; } @@ -351,9 +349,9 @@ public class SubscriptionInfo implements Parcelable { * @return whether the app is authorized to manage this subscription per its metadata. * @throws UnsupportedOperationException if this subscription is not embedded. * @hide - * - * TODO(b/35851809): Make this public. + * @deprecated - Do not use. */ + @Deprecated public boolean canManageSubscription(Context context) { return canManageSubscription(context, context.getPackageName()); } @@ -367,7 +365,9 @@ public class SubscriptionInfo implements Parcelable { * @return whether the app is authorized to manage this subscription per its metadata. * @throws UnsupportedOperationException if this subscription is not embedded. * @hide + * @deprecated - Do not use. */ + @Deprecated public boolean canManageSubscription(Context context, String packageName) { if (!isEmbedded()) { throw new UnsupportedOperationException("Not an embedded subscription"); @@ -395,14 +395,14 @@ public class SubscriptionInfo implements Parcelable { * @return the {@link UiccAccessRule}s dictating who is authorized to manage this subscription. * @throws UnsupportedOperationException if this subscription is not embedded. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ - public @Nullable UiccAccessRule[] getAccessRules() { + @SystemApi + public @Nullable List<UiccAccessRule> getAccessRules() { if (!isEmbedded()) { throw new UnsupportedOperationException("Not an embedded subscription"); } - return mAccessRules; + if (mAccessRules == null) return null; + return Arrays.asList(mAccessRules); } /** diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 137f491b3e09..30e75b9bed91 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -23,6 +23,8 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.net.INetworkPolicyManager; @@ -541,9 +543,9 @@ public class SubscriptionManager { * onSubscriptionsChanged overridden. */ public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { - String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>"; + String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; if (DBG) { - logd("register OnSubscriptionsChangedListener pkgName=" + pkgName + logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug + " listener=" + listener); } try { @@ -552,7 +554,7 @@ public class SubscriptionManager { ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( "telephony.registry")); if (tr != null) { - tr.addOnSubscriptionsChangedListener(pkgName, listener.callback); + tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback); } } catch (RemoteException ex) { // Should not happen @@ -751,10 +753,13 @@ public class SubscriptionManager { * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} * then by {@link SubscriptionInfo#getSubscriptionId}. * </ul> - * @hide * - * TODO(b/35851809): Make this a SystemApi. + * <p> + * Permissions android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE is required + * for #getAvailableSubscriptionInfoList to be invoked. + * @hide */ + @SystemApi public List<SubscriptionInfo> getAvailableSubscriptionInfoList() { List<SubscriptionInfo> result = null; @@ -792,9 +797,6 @@ public class SubscriptionManager { * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} * then by {@link SubscriptionInfo#getSubscriptionId}. * </ul> - * @hide - * - * TODO(b/35851809): Make this public. */ public List<SubscriptionInfo> getAccessibleSubscriptionInfoList() { List<SubscriptionInfo> result = null; @@ -820,9 +822,8 @@ public class SubscriptionManager { * * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ + @SystemApi public void requestEmbeddedSubscriptionInfoListRefresh() { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); @@ -1668,4 +1669,51 @@ public class SubscriptionManager { throw e.rethrowFromSystemServer(); } } + + /** + * Checks whether the app with the given context is authorized to manage the given subscription + * according to its metadata. Only supported for embedded subscriptions (if + * {@code SubscriptionInfo#isEmbedded} returns true). + * + * @param info The subscription to check. + * @return whether the app is authorized to manage this subscription per its metadata. + * @throws UnsupportedOperationException if this subscription is not embedded. + */ + public boolean canManageSubscription(SubscriptionInfo info) { + return canManageSubscription(info, mContext.getPackageName()); + } + + /** + * Checks whether the given app is authorized to manage the given subscription according to its + * metadata. Only supported for embedded subscriptions (if {@code SubscriptionInfo#isEmbedded} + * returns true). + * + * @param info The subscription to check. + * @param packageName Package name of the app to check. + * @return whether the app is authorized to manage this subscription per its metadata. + * @throws UnsupportedOperationException if this subscription is not embedded. + * @hide + */ + public boolean canManageSubscription(SubscriptionInfo info, String packageName) { + if (!info.isEmbedded()) { + throw new UnsupportedOperationException("Not an embedded subscription"); + } + if (info.getAccessRules() == null) { + return false; + } + PackageManager packageManager = mContext.getPackageManager(); + PackageInfo packageInfo; + try { + packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalArgumentException("Unknown package: " + packageName, e); + } + for (UiccAccessRule rule : info.getAccessRules()) { + if (rule.getCarrierPrivilegeStatus(packageInfo) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { + return true; + } + } + return false; + } } diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java index 8c4572474e6b..63263bd37206 100644 --- a/telephony/java/android/telephony/Telephony.java +++ b/telephony/java/android/telephony/Telephony.java @@ -33,6 +33,7 @@ import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SmsMessage; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Patterns; @@ -3345,73 +3346,118 @@ public final class Telephony { } /** - * Contains carrier identification information. - * @hide + * Contains carrier identification information for the current subscriptions. + * @see SubscriptionManager#getActiveSubscriptionIdList() */ public static final class CarrierIdentification implements BaseColumns { /** - * Numeric operator ID (as String). {@code MCC + MNC} - * <P>Type: TEXT </P> - */ - public static final String MCCMNC = "mccmnc"; - - /** - * Group id level 1 (as String). - * <P>Type: TEXT </P> - */ - public static final String GID1 = "gid1"; - - /** - * Group id level 2 (as String). - * <P>Type: TEXT </P> - */ - public static final String GID2 = "gid2"; - - /** - * Public Land Mobile Network name. - * <P>Type: TEXT </P> + * Not instantiable. + * @hide */ - public static final String PLMN = "plmn"; + private CarrierIdentification() {} /** - * Prefix xpattern of IMSI (International Mobile Subscriber Identity). - * <P>Type: TEXT </P> + * The {@code content://} style URI for this provider. */ - public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern"; + public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification"); /** - * Service Provider Name. - * <P>Type: TEXT </P> + * The authority string for the CarrierIdentification Provider + * @hide */ - public static final String SPN = "spn"; + public static final String AUTHORITY = "carrier_identification"; - /** - * Prefer APN name. - * <P>Type: TEXT </P> - */ - public static final String APN = "apn"; /** - * Prefix of Integrated Circuit Card Identifier. - * <P>Type: TEXT </P> + * Generates a content {@link Uri} used to receive updates on carrier identity change + * on the given subscriptionId + * <p> + * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the + * carrier identity {@link TelephonyManager#getAndroidCarrierIdForSubscription()} + * 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 + * updates to the {@link Uri}. + * + * @param subscriptionId the subscriptionId to receive updates on + * @return the Uri used to observe carrier identity changes */ - public static final String ICCID_PREFIX = "iccid_prefix"; + public static Uri getUriForSubscriptionId(int subscriptionId) { + return CONTENT_URI.buildUpon().appendEncodedPath( + String.valueOf(subscriptionId)).build(); + } /** - * User facing carrier name. + * A user facing carrier name. + * @see TelephonyManager#getAndroidCarrierNameForSubscription() * <P>Type: TEXT </P> */ public static final String NAME = "carrier_name"; /** * A unique carrier id + * @see TelephonyManager#getAndroidCarrierIdForSubscription() * <P>Type: INTEGER </P> */ public static final String CID = "carrier_id"; /** - * The {@code content://} URI for this table. + * Contains mappings between matching rules with carrier id for all carriers. + * @hide */ - public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification"); + public static final class All implements BaseColumns { + /** + * Numeric operator ID (as String). {@code MCC + MNC} + * <P>Type: TEXT </P> + */ + public static final String MCCMNC = "mccmnc"; + + /** + * Group id level 1 (as String). + * <P>Type: TEXT </P> + */ + public static final String GID1 = "gid1"; + + /** + * Group id level 2 (as String). + * <P>Type: TEXT </P> + */ + public static final String GID2 = "gid2"; + + /** + * Public Land Mobile Network name. + * <P>Type: TEXT </P> + */ + public static final String PLMN = "plmn"; + + /** + * Prefix xpattern of IMSI (International Mobile Subscriber Identity). + * <P>Type: TEXT </P> + */ + public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern"; + + /** + * Service Provider Name. + * <P>Type: TEXT </P> + */ + public static final String SPN = "spn"; + + /** + * Prefer APN name. + * <P>Type: TEXT </P> + */ + public static final String APN = "apn"; + + /** + * Prefix of Integrated Circuit Card Identifier. + * <P>Type: TEXT </P> + */ + public static final String ICCID_PREFIX = "iccid_prefix"; + + /** + * The {@code content://} URI for this table. + */ + public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification/all"); + } } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 96ed20b841bd..dfccff44f1f0 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -52,6 +52,7 @@ 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; import com.android.ims.internal.IImsServiceFeatureCallback; @@ -892,6 +893,61 @@ public class TelephonyManager { public static final String EVENT_CALL_FORWARDED = "android.telephony.event.EVENT_CALL_FORWARDED"; + /** + * {@link android.telecom.Connection} event used to indicate that a supplementary service + * notification has been received. + * <p> + * Sent via {@link android.telecom.Connection#sendConnectionEvent(String, Bundle)}. + * The {@link Bundle} parameter is expected to include the following extras: + * <ul> + * <li>{@link #EXTRA_NOTIFICATION_TYPE} - the notification type.</li> + * <li>{@link #EXTRA_NOTIFICATION_CODE} - the notification code.</li> + * <li>{@link #EXTRA_NOTIFICATION_MESSAGE} - human-readable message associated with the + * supplementary service notification.</li> + * </ul> + * @hide + */ + public static final String EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION = + "android.telephony.event.EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION"; + + /** + * Integer extra key used with {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} which indicates + * the type of supplementary service notification which occurred. + * Will be either + * {@link com.android.internal.telephony.gsm.SuppServiceNotification#NOTIFICATION_TYPE_CODE_1} + * or + * {@link com.android.internal.telephony.gsm.SuppServiceNotification#NOTIFICATION_TYPE_CODE_2} + * <p> + * Set in the extras for the {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} connection event. + * @hide + */ + public static final String EXTRA_NOTIFICATION_TYPE = + "android.telephony.extra.NOTIFICATION_TYPE"; + + /** + * Integer extra key used with {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} which indicates + * the supplementary service notification which occurred. + * <p> + * Depending on the {@link #EXTRA_NOTIFICATION_TYPE}, the code will be one of the {@code CODE_*} + * codes defined in {@link com.android.internal.telephony.gsm.SuppServiceNotification}. + * <p> + * Set in the extras for the {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} connection event. + * @hide + */ + public static final String EXTRA_NOTIFICATION_CODE = + "android.telephony.extra.NOTIFICATION_CODE"; + + /** + * {@link CharSequence} extra key used with {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} + * which contains a human-readable message which can be displayed to the user for the + * supplementary service notification. + * <p> + * Set in the extras for the {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} connection event. + * @hide + */ + public static final String EXTRA_NOTIFICATION_MESSAGE = + "android.telephony.extra.NOTIFICATION_MESSAGE"; + /* Visual voicemail protocols */ /** @@ -1156,12 +1212,14 @@ public class TelephonyManager { } /** - * Returns the NAI. Return null if NAI is not available. - * + * Returns the Network Access Identifier (NAI). Return null if NAI is not available. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ - /** {@hide}*/ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getNai() { - return getNai(getSlotIndex()); + return getNaiBySubscriberId(getSubId()); } /** @@ -1172,11 +1230,18 @@ public class TelephonyManager { /** {@hide}*/ public String getNai(int slotIndex) { int[] subId = SubscriptionManager.getSubId(slotIndex); + if (subId == null) { + return null; + } + return getNaiBySubscriberId(subId[0]); + } + + private String getNaiBySubscriberId(int subId) { try { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - String nai = info.getNaiForSubscriber(subId[0], mContext.getOpPackageName()); + String nai = info.getNaiForSubscriber(subId, mContext.getOpPackageName()); if (Log.isLoggable(TAG, Log.VERBOSE)) { Rlog.v(TAG, "Nai = " + nai); } @@ -4563,7 +4628,7 @@ public class TelephonyManager { } /** - * Sets the telephony property with the value specified. + * Sets a per-phone telephony property with the value specified. * * @hide */ @@ -4613,6 +4678,20 @@ public class TelephonyManager { } /** + * Sets a global telephony property with the value specified. + * + * @hide + */ + public static void setTelephonyProperty(String property, String value) { + if (value == null) { + value = ""; + } + Rlog.d(TAG, "setTelephonyProperty: success" + " property=" + + property + " value: " + value); + SystemProperties.set(property, value); + } + + /** * Convenience function for retrieving a value from the secure settings * value list as an integer. Note that internally setting values are * always stored as strings; this function converts the string to an @@ -4701,7 +4780,7 @@ public class TelephonyManager { } /** - * Gets the telephony property. + * Gets a per-phone telephony property. * * @hide */ @@ -4717,6 +4796,19 @@ public class TelephonyManager { return propVal == null ? defaultVal : propVal; } + /** + * Gets a global telephony property. + * + * See also getTelephonyProperty(phoneId, property, defaultVal). Most telephony properties are + * per-phone. + * + * @hide + */ + public static String getTelephonyProperty(String property, String defaultVal) { + String propVal = SystemProperties.get(property); + return propVal == null ? defaultVal : propVal; + } + /** @hide */ public int getSimCount() { // FIXME Need to get it from Telephony Dev Controller when that gets implemented! @@ -6145,84 +6237,106 @@ public class TelephonyManager { return false; } - /** - * Returns the IMS Registration Status - * @hide - */ - public boolean isImsRegistered() { - try { - ITelephony telephony = getITelephony(); - if (telephony == null) - return false; - return telephony.isImsRegistered(); - } catch (RemoteException ex) { - return false; - } catch (NullPointerException ex) { - return false; - } - } - /** - * Returns the IMS Registration Status for a particular Subscription ID + * Returns the IMS Registration Status for a particular Subscription ID. * * @param subId Subscription ID * @return true if IMS status is registered, false if the IMS status is not registered or a * RemoteException occurred. - * * @hide */ public boolean isImsRegistered(int subId) { + try { + return getITelephony().isImsRegistered(subId); + } catch (RemoteException | NullPointerException ex) { + return false; + } + } + + /** + * Returns the IMS Registration Status for a particular Subscription ID, which is determined + * when the TelephonyManager is created using {@link #createForSubscriptionId(int)}. If an + * invalid subscription ID is used during creation, will the default subscription ID will be + * used. + * + * @return true if IMS status is registered, false if the IMS status is not registered or a + * RemoteException occurred. + * @see SubscriptionManager#getDefaultSubscriptionId() + * @hide + */ + public boolean isImsRegistered() { try { - return getITelephony().isImsRegisteredForSubscriber(subId); - } catch (RemoteException ex) { - return false; - } catch (NullPointerException ex) { + return getITelephony().isImsRegistered(getSubId()); + } catch (RemoteException | NullPointerException ex) { return false; } } /** - * Returns the Status of Volte + * The current status of Voice over LTE for the subscription associated with this instance when + * it was created using {@link #createForSubscriptionId(int)}. If an invalid subscription ID was + * used during creation, the default subscription ID will be used. + * @return true if Voice over LTE is available or false if it is unavailable or unknown. + * @see SubscriptionManager#getDefaultSubscriptionId() * @hide */ public boolean isVolteAvailable() { - try { - return getITelephony().isVolteAvailable(); - } catch (RemoteException ex) { - return false; - } catch (NullPointerException ex) { - return false; - } - } + try { + return getITelephony().isVolteAvailable(getSubId()); + } catch (RemoteException | NullPointerException ex) { + return false; + } + } /** - * Returns the Status of video telephony (VT) + * The availability of Video Telephony (VT) for the subscription ID specified when this instance + * was created using {@link #createForSubscriptionId(int)}. If an invalid subscription ID was + * used during creation, the default subscription ID will be used. To query the + * underlying technology that VT is available on, use {@link #getImsRegTechnologyForMmTel}. + * @return true if VT is available, or false if it is unavailable or unknown. * @hide */ public boolean isVideoTelephonyAvailable() { try { - return getITelephony().isVideoTelephonyAvailable(); - } catch (RemoteException ex) { - return false; - } catch (NullPointerException ex) { + return getITelephony().isVideoTelephonyAvailable(getSubId()); + } catch (RemoteException | NullPointerException ex) { return false; } } /** - * Returns the Status of Wi-Fi Calling + * Returns the Status of Wi-Fi calling (Voice over WiFi) for the subscription ID specified. + * @param subId the subscription ID. + * @return true if VoWiFi is available, or false if it is unavailable or unknown. * @hide */ public boolean isWifiCallingAvailable() { try { - return getITelephony().isWifiCallingAvailable(); - } catch (RemoteException ex) { - return false; - } catch (NullPointerException ex) { + return getITelephony().isWifiCallingAvailable(getSubId()); + } catch (RemoteException | NullPointerException ex) { return false; } } + /** + * The technology that IMS is registered for for the MMTEL feature. + * @param subId subscription ID to get IMS registration technology for. + * @return The IMS registration technology that IMS is registered to for the MMTEL feature. + * Valid return results are: + * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} for LTE registration, + * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} for IWLAN registration, or + * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_NONE} if we are not registered or the + * result is unavailable. + * @hide + */ + public @ImsRegistrationImplBase.ImsRegistrationTech int getImsRegTechnologyForMmTel() { + try { + return getITelephony().getImsRegTechnologyForMmTel(getSubId()); + } catch (RemoteException ex) { + return ImsRegistrationImplBase.REGISTRATION_TECH_NONE; + } + } + /** * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone. * diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java index 39372019c20f..c3f8a1930409 100644 --- a/telephony/java/android/telephony/UiccAccessRule.java +++ b/telephony/java/android/telephony/UiccAccessRule.java @@ -16,6 +16,7 @@ package android.telephony; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.content.pm.PackageInfo; import android.content.pm.Signature; import android.os.Parcel; @@ -39,9 +40,8 @@ import java.util.Objects; * specification. * * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ +@SystemApi public final class UiccAccessRule implements Parcelable { private static final String TAG = "UiccAccessRule"; diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java index 0b3cbad0d2e2..0c17147ca3fa 100644 --- a/telephony/java/android/telephony/UiccSlotInfo.java +++ b/telephony/java/android/telephony/UiccSlotInfo.java @@ -55,10 +55,11 @@ public class UiccSlotInfo implements Parcelable { /** Card state restricted. */ public static final int CARD_STATE_INFO_RESTRICTED = 4; - public final boolean isActive; - public final boolean isEuicc; - public final String cardId; - public final @CardStateInfo int cardStateInfo; + private final boolean mIsActive; + private final boolean mIsEuicc; + private final String mCardId; + private final @CardStateInfo int mCardStateInfo; + private final int mLogicalSlotIdx; public static final Creator<UiccSlotInfo> CREATOR = new Creator<UiccSlotInfo>() { @Override @@ -73,18 +74,20 @@ public class UiccSlotInfo implements Parcelable { }; private UiccSlotInfo(Parcel in) { - isActive = in.readByte() != 0; - isEuicc = in.readByte() != 0; - cardId = in.readString(); - cardStateInfo = in.readInt(); + mIsActive = in.readByte() != 0; + mIsEuicc = in.readByte() != 0; + mCardId = in.readString(); + mCardStateInfo = in.readInt(); + mLogicalSlotIdx = in.readInt(); } @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeByte((byte) (isActive ? 1 : 0)); - dest.writeByte((byte) (isEuicc ? 1 : 0)); - dest.writeString(cardId); - dest.writeInt(cardStateInfo); + dest.writeByte((byte) (mIsActive ? 1 : 0)); + dest.writeByte((byte) (mIsEuicc ? 1 : 0)); + dest.writeString(mCardId); + dest.writeInt(mCardStateInfo); + dest.writeInt(mLogicalSlotIdx); } @Override @@ -93,28 +96,33 @@ public class UiccSlotInfo implements Parcelable { } public UiccSlotInfo(boolean isActive, boolean isEuicc, String cardId, - @CardStateInfo int cardStateInfo) { - this.isActive = isActive; - this.isEuicc = isEuicc; - this.cardId = cardId; - this.cardStateInfo = cardStateInfo; + @CardStateInfo int cardStateInfo, int logicalSlotIdx) { + this.mIsActive = isActive; + this.mIsEuicc = isEuicc; + this.mCardId = cardId; + this.mCardStateInfo = cardStateInfo; + this.mLogicalSlotIdx = logicalSlotIdx; } public boolean getIsActive() { - return isActive; + return mIsActive; } public boolean getIsEuicc() { - return isEuicc; + return mIsEuicc; } public String getCardId() { - return cardId; + return mCardId; } @CardStateInfo public int getCardStateInfo() { - return cardStateInfo; + return mCardStateInfo; + } + + public int getLogicalSlotIdx() { + return mLogicalSlotIdx; } @Override @@ -127,32 +135,36 @@ public class UiccSlotInfo implements Parcelable { } UiccSlotInfo that = (UiccSlotInfo) obj; - return (isActive == that.isActive) - && (isEuicc == that.isEuicc) - && (cardId == that.cardId) - && (cardStateInfo == that.cardStateInfo); + return (mIsActive == that.mIsActive) + && (mIsEuicc == that.mIsEuicc) + && (mCardId == that.mCardId) + && (mCardStateInfo == that.mCardStateInfo) + && (mLogicalSlotIdx == that.mLogicalSlotIdx); } @Override public int hashCode() { int result = 1; - result = 31 * result + (isActive ? 1 : 0); - result = 31 * result + (isEuicc ? 1 : 0); - result = 31 * result + Objects.hashCode(cardId); - result = 31 * result + cardStateInfo; + result = 31 * result + (mIsActive ? 1 : 0); + result = 31 * result + (mIsEuicc ? 1 : 0); + result = 31 * result + Objects.hashCode(mCardId); + result = 31 * result + mCardStateInfo; + result = 31 * result + mLogicalSlotIdx; return result; } @Override public String toString() { - return "UiccSlotInfo (isActive=" - + isActive - + ", isEuicc=" - + isEuicc - + ", cardId=" - + cardId + return "UiccSlotInfo (mIsActive=" + + mIsActive + + ", mIsEuicc=" + + mIsEuicc + + ", mCardId=" + + mCardId + ", cardState=" - + cardStateInfo + + mCardStateInfo + + ", phoneId=" + + mLogicalSlotIdx + ")"; } } diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java index 01041c8b1360..88db22b82c5c 100644 --- a/telephony/java/android/telephony/euicc/DownloadableSubscription.java +++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java @@ -16,18 +16,17 @@ package android.telephony.euicc; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.telephony.UiccAccessRule; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import com.android.internal.util.Preconditions; -/** - * Information about a subscription which is available for download. - * - * TODO(b/35851809): Make this public. - * @hide - */ +/** Information about a subscription which is available for download. */ public final class DownloadableSubscription implements Parcelable { public static final Creator<DownloadableSubscription> CREATOR = @@ -46,11 +45,12 @@ public final class DownloadableSubscription implements Parcelable { /** * Activation code. May be null for subscriptions which are not based on activation codes, e.g. * to download a default subscription assigned to this device. + * Should use getEncodedActivationCode() instead. * @hide - * - * TODO(b/35851809): Make this a SystemApi. + * @deprecated - Do not use. This will be private. Use getEncodedActivationCode() instead. */ @Nullable + @Deprecated public final String encodedActivationCode; @Nullable private String confirmationCode; @@ -58,8 +58,16 @@ public final class DownloadableSubscription implements Parcelable { // see getCarrierName and setCarrierName @Nullable private String carrierName; + // see getAccessRules and setAccessRules - private UiccAccessRule[] accessRules; + @Nullable + private List<UiccAccessRule> accessRules; + + /** Gets the activation code. */ + @Nullable + public String getEncodedActivationCode() { + return encodedActivationCode; + } /** @hide */ private DownloadableSubscription(String encodedActivationCode) { @@ -70,7 +78,59 @@ public final class DownloadableSubscription implements Parcelable { encodedActivationCode = in.readString(); confirmationCode = in.readString(); carrierName = in.readString(); - accessRules = in.createTypedArray(UiccAccessRule.CREATOR); + accessRules = new ArrayList<UiccAccessRule>(); + in.readTypedList(accessRules, UiccAccessRule.CREATOR); + } + + private DownloadableSubscription(String encodedActivationCode, String confirmationCode, + String carrierName, List<UiccAccessRule> accessRules) { + this.encodedActivationCode = encodedActivationCode; + this.confirmationCode = confirmationCode; + this.carrierName = carrierName; + this.accessRules = accessRules; + } + + /** @hide */ + @SystemApi + public static final class Builder { + @Nullable private String encodedActivationCode; + @Nullable private String confirmationCode; + @Nullable private String carrierName; + List<UiccAccessRule> accessRules; + + public Builder() {} + + public Builder(DownloadableSubscription baseSubscription) { + encodedActivationCode = baseSubscription.getEncodedActivationCode(); + confirmationCode = baseSubscription.getConfirmationCode(); + carrierName = baseSubscription.getCarrierName(); + accessRules = baseSubscription.getAccessRules(); + } + + public DownloadableSubscription build() { + return new DownloadableSubscription(encodedActivationCode, confirmationCode, + carrierName, accessRules); + } + + public Builder setEncodedActivationCode(String value) { + encodedActivationCode = value; + return this; + } + + public Builder setConfirmationCode(String value) { + confirmationCode = value; + return this; + } + + public Builder setCarrierName(String value) { + carrierName = value; + return this; + } + + public Builder setAccessRules(List<UiccAccessRule> value) { + accessRules = value; + return this; + } } /** @@ -87,7 +147,10 @@ public final class DownloadableSubscription implements Parcelable { /** * Sets the confirmation code. + * @hide + * @deprecated - Do not use. */ + @Deprecated public void setConfirmationCode(String confirmationCode) { this.confirmationCode = confirmationCode; } @@ -103,9 +166,9 @@ public final class DownloadableSubscription implements Parcelable { /** * Set the user-visible carrier name. * @hide - * - * TODO(b/35851809): Make this a SystemApi. + * @deprecated - Do not use. */ + @Deprecated public void setCarrierName(String carrierName) { this.carrierName = carrierName; } @@ -117,44 +180,51 @@ public final class DownloadableSubscription implements Parcelable { * those created with {@link #forActivationCode}). May be populated with * {@link EuiccManager#getDownloadableSubscriptionMetadata}. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ + @SystemApi @Nullable public String getCarrierName() { return carrierName; } /** - * Returns the {@link UiccAccessRule}s dictating access to this subscription. + * Returns the {@link UiccAccessRule}s in list dictating access to this subscription. * * <p>Only present for downloadable subscriptions that were queried from a server (as opposed to * those created with {@link #forActivationCode}). May be populated with * {@link EuiccManager#getDownloadableSubscriptionMetadata}. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ - public UiccAccessRule[] getAccessRules() { + @SystemApi + public List<UiccAccessRule> getAccessRules() { return accessRules; } /** * Set the {@link UiccAccessRule}s dictating access to this subscription. * @hide - * - * TODO(b/35851809): Make this a SystemApi. + * @deprecated - Do not use. */ - public void setAccessRules(UiccAccessRule[] accessRules) { + @Deprecated + public void setAccessRules(List<UiccAccessRule> accessRules) { this.accessRules = accessRules; } + /** + * @hide + * @deprecated - Do not use. + */ + @Deprecated + public void setAccessRules(UiccAccessRule[] accessRules) { + this.accessRules = Arrays.asList(accessRules); + } + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(encodedActivationCode); dest.writeString(confirmationCode); dest.writeString(carrierName); - dest.writeTypedArray(accessRules, flags); + dest.writeTypedList(accessRules); } @Override diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java index a1a6a5a4d5bb..6be77250996e 100644 --- a/telephony/java/android/telephony/euicc/EuiccCardManager.java +++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java @@ -17,6 +17,7 @@ package android.telephony.euicc; import android.annotation.IntDef; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; @@ -49,14 +50,13 @@ import com.android.internal.telephony.euicc.ISwitchToProfileCallback; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; /** * EuiccCardManager is the application interface to an eSIM card. - * * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ +@SystemApi public class EuiccCardManager { private static final String TAG = "EuiccCardManager"; @@ -68,6 +68,7 @@ public class EuiccCardManager { CANCEL_REASON_TIMEOUT, CANCEL_REASON_PPR_NOT_ALLOWED }) + /** @hide */ public @interface CancelReason {} /** @@ -96,6 +97,7 @@ public class EuiccCardManager { RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS }) + /** @hide */ public @interface ResetOption {} /** Deletes all operational profiles. */ @@ -143,18 +145,20 @@ public class EuiccCardManager { } /** - * Gets all the profiles on eUicc. + * Requests all the profiles on eUicc. * * @param cardId The Id of the eUICC. + * @param executor The executor through which the callback should be invode. * @param callback The callback to get the result code and all the profiles. */ - public void getAllProfiles(String cardId, ResultCallback<EuiccProfileInfo[]> callback) { + public void requestAllProfiles(String cardId, Executor executor, + ResultCallback<EuiccProfileInfo[]> callback) { try { getIEuiccCardController().getAllProfiles(mContext.getOpPackageName(), cardId, new IGetAllProfilesCallback.Stub() { @Override public void onComplete(int resultCode, EuiccProfileInfo[] profiles) { - callback.onComplete(resultCode, profiles); + executor.execute(() -> callback.onComplete(resultCode, profiles)); } }); } catch (RemoteException e) { @@ -164,19 +168,21 @@ public class EuiccCardManager { } /** - * Gets the profile of the given iccid. + * Requests the profile of the given iccid. * * @param cardId The Id of the eUICC. * @param iccid The iccid of the profile. + * @param executor The executor through which the callback should be invode. * @param callback The callback to get the result code and profile. */ - public void getProfile(String cardId, String iccid, ResultCallback<EuiccProfileInfo> callback) { + public void requestProfile(String cardId, String iccid, Executor executor, + ResultCallback<EuiccProfileInfo> callback) { try { getIEuiccCardController().getProfile(mContext.getOpPackageName(), cardId, iccid, new IGetProfileCallback.Stub() { @Override public void onComplete(int resultCode, EuiccProfileInfo profile) { - callback.onComplete(resultCode, profile); + executor.execute(() -> callback.onComplete(resultCode, profile)); } }); } catch (RemoteException e) { @@ -191,16 +197,17 @@ public class EuiccCardManager { * @param cardId The Id of the eUICC. * @param iccid The iccid of the profile. * @param refresh Whether sending the REFRESH command to modem. + * @param executor The executor through which the callback should be invode. * @param callback The callback to get the result code. */ - public void disableProfile(String cardId, String iccid, boolean refresh, + public void disableProfile(String cardId, String iccid, boolean refresh, Executor executor, ResultCallback<Void> callback) { try { getIEuiccCardController().disableProfile(mContext.getOpPackageName(), cardId, iccid, refresh, new IDisableProfileCallback.Stub() { @Override public void onComplete(int resultCode) { - callback.onComplete(resultCode, null); + executor.execute(() -> callback.onComplete(resultCode, null)); } }); } catch (RemoteException e) { @@ -216,16 +223,17 @@ public class EuiccCardManager { * @param cardId The Id of the eUICC. * @param iccid The iccid of the profile to switch to. * @param refresh Whether sending the REFRESH command to modem. + * @param executor The executor through which the callback should be invode. * @param callback The callback to get the result code and the EuiccProfileInfo enabled. */ - public void switchToProfile(String cardId, String iccid, boolean refresh, + public void switchToProfile(String cardId, String iccid, boolean refresh, Executor executor, ResultCallback<EuiccProfileInfo> callback) { try { getIEuiccCardController().switchToProfile(mContext.getOpPackageName(), cardId, iccid, refresh, new ISwitchToProfileCallback.Stub() { @Override public void onComplete(int resultCode, EuiccProfileInfo profile) { - callback.onComplete(resultCode, profile); + executor.execute(() -> callback.onComplete(resultCode, profile)); } }); } catch (RemoteException e) { @@ -240,16 +248,17 @@ public class EuiccCardManager { * @param cardId The Id of the eUICC. * @param iccid The iccid of the profile. * @param nickname The nickname of the profile. + * @param executor The executor through which the callback should be invode. * @param callback The callback to get the result code. */ - public void setNickname(String cardId, String iccid, String nickname, + public void setNickname(String cardId, String iccid, String nickname, Executor executor, ResultCallback<Void> callback) { try { getIEuiccCardController().setNickname(mContext.getOpPackageName(), cardId, iccid, nickname, new ISetNicknameCallback.Stub() { @Override public void onComplete(int resultCode) { - callback.onComplete(resultCode, null); + executor.execute(() -> callback.onComplete(resultCode, null)); } }); } catch (RemoteException e) { @@ -263,15 +272,17 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param iccid The iccid of the profile. + * @param executor The executor through which the callback should be invode. * @param callback The callback to get the result code. */ - public void deleteProfile(String cardId, String iccid, ResultCallback<Void> callback) { + public void deleteProfile(String cardId, String iccid, Executor executor, + ResultCallback<Void> callback) { try { getIEuiccCardController().deleteProfile(mContext.getOpPackageName(), cardId, iccid, new IDeleteProfileCallback.Stub() { @Override public void onComplete(int resultCode) { - callback.onComplete(resultCode, null); + executor.execute(() -> callback.onComplete(resultCode, null)); } }); } catch (RemoteException e) { @@ -286,15 +297,17 @@ public class EuiccCardManager { * @param cardId The Id of the eUICC. * @param options Bits of the options of resetting which parts of the eUICC memory. See * EuiccCard for details. + * @param executor The executor through which the callback should be invode. * @param callback The callback to get the result code. */ - public void resetMemory(String cardId, @ResetOption int options, ResultCallback<Void> callback) { + public void resetMemory(String cardId, @ResetOption int options, Executor executor, + ResultCallback<Void> callback) { try { getIEuiccCardController().resetMemory(mContext.getOpPackageName(), cardId, options, new IResetMemoryCallback.Stub() { @Override public void onComplete(int resultCode) { - callback.onComplete(resultCode, null); + executor.execute(() -> callback.onComplete(resultCode, null)); } }); } catch (RemoteException e) { @@ -304,18 +317,20 @@ public class EuiccCardManager { } /** - * Gets the default SM-DP+ address from eUICC. + * Requests the default SM-DP+ address from eUICC. * * @param cardId The Id of the eUICC. + * @param executor The executor through which the callback should be invode. * @param callback The callback to get the result code and the default SM-DP+ address. */ - public void getDefaultSmdpAddress(String cardId, ResultCallback<String> callback) { + public void requestDefaultSmdpAddress(String cardId, Executor executor, + ResultCallback<String> callback) { try { getIEuiccCardController().getDefaultSmdpAddress(mContext.getOpPackageName(), cardId, new IGetDefaultSmdpAddressCallback.Stub() { @Override public void onComplete(int resultCode, String address) { - callback.onComplete(resultCode, address); + executor.execute(() -> callback.onComplete(resultCode, address)); } }); } catch (RemoteException e) { @@ -325,18 +340,20 @@ public class EuiccCardManager { } /** - * Gets the SM-DS address from eUICC. + * Requests the SM-DS address from eUICC. * * @param cardId The Id of the eUICC. + * @param executor The executor through which the callback should be invode. * @param callback The callback to get the result code and the SM-DS address. */ - public void getSmdsAddress(String cardId, ResultCallback<String> callback) { + public void requestSmdsAddress(String cardId, Executor executor, + ResultCallback<String> callback) { try { getIEuiccCardController().getSmdsAddress(mContext.getOpPackageName(), cardId, new IGetSmdsAddressCallback.Stub() { @Override public void onComplete(int resultCode, String address) { - callback.onComplete(resultCode, address); + executor.execute(() -> callback.onComplete(resultCode, address)); } }); } catch (RemoteException e) { @@ -350,16 +367,18 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param defaultSmdpAddress The default SM-DP+ address to set. + * @param executor The executor through which the callback should be invode. * @param callback The callback to get the result code. */ - public void setDefaultSmdpAddress(String cardId, String defaultSmdpAddress, ResultCallback<Void> callback) { + public void setDefaultSmdpAddress(String cardId, String defaultSmdpAddress, Executor executor, + ResultCallback<Void> callback) { try { getIEuiccCardController().setDefaultSmdpAddress(mContext.getOpPackageName(), cardId, defaultSmdpAddress, new ISetDefaultSmdpAddressCallback.Stub() { @Override public void onComplete(int resultCode) { - callback.onComplete(resultCode, null); + executor.execute(() -> callback.onComplete(resultCode, null)); } }); } catch (RemoteException e) { @@ -369,18 +388,20 @@ public class EuiccCardManager { } /** - * Gets Rules Authorisation Table. + * Requests Rules Authorisation Table. * * @param cardId The Id of the eUICC. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and the rule authorisation table. */ - public void getRulesAuthTable(String cardId, ResultCallback<EuiccRulesAuthTable> callback) { + public void requestRulesAuthTable(String cardId, Executor executor, + ResultCallback<EuiccRulesAuthTable> callback) { try { getIEuiccCardController().getRulesAuthTable(mContext.getOpPackageName(), cardId, new IGetRulesAuthTableCallback.Stub() { @Override public void onComplete(int resultCode, EuiccRulesAuthTable rat) { - callback.onComplete(resultCode, rat); + executor.execute(() -> callback.onComplete(resultCode, rat)); } }); } catch (RemoteException e) { @@ -390,18 +411,20 @@ public class EuiccCardManager { } /** - * Gets the eUICC challenge for new profile downloading. + * Requests the eUICC challenge for new profile downloading. * * @param cardId The Id of the eUICC. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and the challenge. */ - public void getEuiccChallenge(String cardId, ResultCallback<byte[]> callback) { + public void requestEuiccChallenge(String cardId, Executor executor, + ResultCallback<byte[]> callback) { try { getIEuiccCardController().getEuiccChallenge(mContext.getOpPackageName(), cardId, new IGetEuiccChallengeCallback.Stub() { @Override public void onComplete(int resultCode, byte[] challenge) { - callback.onComplete(resultCode, challenge); + executor.execute(() -> callback.onComplete(resultCode, challenge)); } }); } catch (RemoteException e) { @@ -411,18 +434,20 @@ public class EuiccCardManager { } /** - * Gets the eUICC info1 defined in GSMA RSP v2.0+ for new profile downloading. + * Requests the eUICC info1 defined in GSMA RSP v2.0+ for new profile downloading. * * @param cardId The Id of the eUICC. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and the info1. */ - public void getEuiccInfo1(String cardId, ResultCallback<byte[]> callback) { + public void requestEuiccInfo1(String cardId, Executor executor, + ResultCallback<byte[]> callback) { try { getIEuiccCardController().getEuiccInfo1(mContext.getOpPackageName(), cardId, new IGetEuiccInfo1Callback.Stub() { @Override public void onComplete(int resultCode, byte[] info) { - callback.onComplete(resultCode, info); + executor.execute(() -> callback.onComplete(resultCode, info)); } }); } catch (RemoteException e) { @@ -435,15 +460,17 @@ public class EuiccCardManager { * Gets the eUICC info2 defined in GSMA RSP v2.0+ for new profile downloading. * * @param cardId The Id of the eUICC. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and the info2. */ - public void getEuiccInfo2(String cardId, ResultCallback<byte[]> callback) { + public void requestEuiccInfo2(String cardId, Executor executor, + ResultCallback<byte[]> callback) { try { getIEuiccCardController().getEuiccInfo2(mContext.getOpPackageName(), cardId, new IGetEuiccInfo2Callback.Stub() { @Override public void onComplete(int resultCode, byte[] info) { - callback.onComplete(resultCode, info); + executor.execute(() -> callback.onComplete(resultCode, info)); } }); } catch (RemoteException e) { @@ -466,12 +493,13 @@ public class EuiccCardManager { * GSMA RSP v2.0+. * @param serverCertificate ASN.1 data in byte array indicating SM-DP+ Certificate returned by * SM-DP+ server. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and a byte array which represents a * {@code AuthenticateServerResponse} defined in GSMA RSP v2.0+. */ public void authenticateServer(String cardId, String matchingId, byte[] serverSigned1, byte[] serverSignature1, byte[] euiccCiPkIdToBeUsed, byte[] serverCertificate, - ResultCallback<byte[]> callback) { + Executor executor, ResultCallback<byte[]> callback) { try { getIEuiccCardController().authenticateServer( mContext.getOpPackageName(), @@ -484,7 +512,7 @@ public class EuiccCardManager { new IAuthenticateServerCallback.Stub() { @Override public void onComplete(int resultCode, byte[] response) { - callback.onComplete(resultCode, response); + executor.execute(() -> callback.onComplete(resultCode, response)); } }); } catch (RemoteException e) { @@ -505,11 +533,13 @@ public class EuiccCardManager { * SM-DP+ server. * @param smdpCertificate ASN.1 data in byte array indicating the SM-DP+ Certificate returned * by SM-DP+ server. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and a byte array which represents a * {@code PrepareDownloadResponse} defined in GSMA RSP v2.0+ */ public void prepareDownload(String cardId, @Nullable byte[] hashCc, byte[] smdpSigned2, - byte[] smdpSignature2, byte[] smdpCertificate, ResultCallback<byte[]> callback) { + byte[] smdpSignature2, byte[] smdpCertificate, Executor executor, + ResultCallback<byte[]> callback) { try { getIEuiccCardController().prepareDownload( mContext.getOpPackageName(), @@ -521,7 +551,7 @@ public class EuiccCardManager { new IPrepareDownloadCallback.Stub() { @Override public void onComplete(int resultCode, byte[] response) { - callback.onComplete(resultCode, response); + executor.execute(() -> callback.onComplete(resultCode, response)); } }); } catch (RemoteException e) { @@ -535,11 +565,12 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param boundProfilePackage the Bound Profile Package data returned by SM-DP+ server. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and a byte array which represents a * {@code LoadBoundProfilePackageResponse} defined in GSMA RSP v2.0+. */ public void loadBoundProfilePackage(String cardId, byte[] boundProfilePackage, - ResultCallback<byte[]> callback) { + Executor executor, ResultCallback<byte[]> callback) { try { getIEuiccCardController().loadBoundProfilePackage( mContext.getOpPackageName(), @@ -548,7 +579,7 @@ public class EuiccCardManager { new ILoadBoundProfilePackageCallback.Stub() { @Override public void onComplete(int resultCode, byte[] response) { - callback.onComplete(resultCode, response); + executor.execute(() -> callback.onComplete(resultCode, response)); } }); } catch (RemoteException e) { @@ -563,11 +594,12 @@ public class EuiccCardManager { * @param cardId The Id of the eUICC. * @param transactionId the transaction ID returned by SM-DP+ server. * @param reason the cancel reason. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and an byte[] which represents a * {@code CancelSessionResponse} defined in GSMA RSP v2.0+. */ public void cancelSession(String cardId, byte[] transactionId, @CancelReason int reason, - ResultCallback<byte[]> callback) { + Executor executor, ResultCallback<byte[]> callback) { try { getIEuiccCardController().cancelSession( mContext.getOpPackageName(), @@ -577,7 +609,7 @@ public class EuiccCardManager { new ICancelSessionCallback.Stub() { @Override public void onComplete(int resultCode, byte[] response) { - callback.onComplete(resultCode, response); + executor.execute(() -> callback.onComplete(resultCode, response)); } }); } catch (RemoteException e) { @@ -591,16 +623,17 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param events bits of the event types ({@link EuiccNotification.Event}) to list. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and the list of notifications. */ public void listNotifications(String cardId, @EuiccNotification.Event int events, - ResultCallback<EuiccNotification[]> callback) { + Executor executor, ResultCallback<EuiccNotification[]> callback) { try { getIEuiccCardController().listNotifications(mContext.getOpPackageName(), cardId, events, new IListNotificationsCallback.Stub() { @Override public void onComplete(int resultCode, EuiccNotification[] notifications) { - callback.onComplete(resultCode, notifications); + executor.execute(() -> callback.onComplete(resultCode, notifications)); } }); } catch (RemoteException e) { @@ -614,16 +647,17 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param events bits of the event types ({@link EuiccNotification.Event}) to list. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and the list of notifications. */ public void retrieveNotificationList(String cardId, @EuiccNotification.Event int events, - ResultCallback<EuiccNotification[]> callback) { + Executor executor, ResultCallback<EuiccNotification[]> callback) { try { getIEuiccCardController().retrieveNotificationList(mContext.getOpPackageName(), cardId, events, new IRetrieveNotificationListCallback.Stub() { @Override public void onComplete(int resultCode, EuiccNotification[] notifications) { - callback.onComplete(resultCode, notifications); + executor.execute(() -> callback.onComplete(resultCode, notifications)); } }); } catch (RemoteException e) { @@ -637,16 +671,17 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param seqNumber the sequence number of the notification. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code and the notification. */ - public void retrieveNotification(String cardId, int seqNumber, + public void retrieveNotification(String cardId, int seqNumber, Executor executor, ResultCallback<EuiccNotification> callback) { try { getIEuiccCardController().retrieveNotification(mContext.getOpPackageName(), cardId, seqNumber, new IRetrieveNotificationCallback.Stub() { @Override public void onComplete(int resultCode, EuiccNotification notification) { - callback.onComplete(resultCode, notification); + executor.execute(() -> callback.onComplete(resultCode, notification)); } }); } catch (RemoteException e) { @@ -660,9 +695,10 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param seqNumber the sequence number of the notification. + * @param executor The executor through which the callback should be invode. * @param callback the callback to get the result code. */ - public void removeNotificationFromList(String cardId, int seqNumber, + public void removeNotificationFromList(String cardId, int seqNumber, Executor executor, ResultCallback<Void> callback) { try { getIEuiccCardController().removeNotificationFromList( @@ -672,7 +708,7 @@ public class EuiccCardManager { new IRemoveNotificationFromListCallback.Stub() { @Override public void onComplete(int resultCode) { - callback.onComplete(resultCode, null); + executor.execute(() -> callback.onComplete(resultCode, null)); } }); } catch (RemoteException e) { diff --git a/telephony/java/android/telephony/euicc/EuiccInfo.java b/telephony/java/android/telephony/euicc/EuiccInfo.java index 5bfff08f8d45..a4adf0591a00 100644 --- a/telephony/java/android/telephony/euicc/EuiccInfo.java +++ b/telephony/java/android/telephony/euicc/EuiccInfo.java @@ -23,9 +23,6 @@ import android.os.Parcelable; * Information about an eUICC chip/device. * * @see EuiccManager#getEuiccInfo - * @hide - * - * TODO(b/35851809): Make this public. */ // WARNING: Do not add any privacy-sensitive fields to this class (such as an eUICC identifier)! // This API is accessible to all applications. Privacy-sensitive fields should be returned in their @@ -45,12 +42,17 @@ public final class EuiccInfo implements Parcelable { } }; + @Nullable + private final String osVersion; + /** - * Version of the operating system running on the eUICC. This field is hardware-specific and is - * not guaranteed to match any particular format. + * Gets the version of the operating system running on the eUICC. This field is + * hardware-specific and is not guaranteed to match any particular format. */ @Nullable - public final String osVersion; + public String getOsVersion() { + return osVersion; + } public EuiccInfo(@Nullable String osVersion) { this.osVersion = osVersion; diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index 662056e90496..71ef5de92e7b 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -42,9 +42,6 @@ import java.lang.annotation.RetentionPolicy; * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}. * * <p>See {@link #isEnabled} before attempting to use these APIs. - * - * TODO(b/35851809): Make this public. - * @hide */ public class EuiccManager { @@ -56,6 +53,8 @@ public class EuiccManager { * * <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if * {@link #isEnabled} is false. + * + * This is ued by non-LPA app to bring up LUI. */ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = @@ -69,8 +68,10 @@ public class EuiccManager { * * <p class="note">This is a protected intent that can only be sent * by the system. - * TODO(b/35851809): Make this a SystemApi. + * + * @hide */ + @SystemApi @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED"; @@ -78,12 +79,10 @@ public class EuiccManager { /** * Broadcast Action: The action sent to carrier app so it knows the carrier setup is not * completed. - * - * TODO(b/35851809): Make this a public API. */ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_NOTIFY_CARRIER_SETUP = - "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP"; + public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = + "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE"; /** * Intent action to provision an embedded subscription. @@ -95,8 +94,9 @@ public class EuiccManager { * <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if * {@link #isEnabled} is false or if the device is already provisioned. * - * TODO(b/35851809): Make this a SystemApi. + * @hide */ + @SystemApi @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; @@ -143,9 +143,8 @@ public class EuiccManager { * Key for an extra set on {@link #getDownloadableSubscriptionMetadata} PendingIntent result * callbacks providing the downloadable subscription metadata. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ + @SystemApi public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION"; @@ -153,9 +152,8 @@ public class EuiccManager { * Key for an extra set on {@link #getDefaultDownloadableSubscriptionList} PendingIntent result * callbacks providing the list of available downloadable subscriptions. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ + @SystemApi public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS"; @@ -201,6 +199,7 @@ public class EuiccManager { * Euicc OTA update status which can be got by {@link #getOtaStatus} * @hide */ + @SystemApi @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"EUICC_OTA_"}, value = { EUICC_OTA_IN_PROGRESS, @@ -215,15 +214,37 @@ public class EuiccManager { /** * An OTA is in progress. During this time, the eUICC is not available and the user may lose * network access. + * @hide */ + @SystemApi public static final int EUICC_OTA_IN_PROGRESS = 1; - /** The OTA update failed. */ + + /** + * The OTA update failed. + * @hide + */ + @SystemApi public static final int EUICC_OTA_FAILED = 2; - /** The OTA update finished successfully. */ + + /** + * The OTA update finished successfully. + * @hide + */ + @SystemApi public static final int EUICC_OTA_SUCCEEDED = 3; - /** The OTA update not needed since current eUICC OS is latest. */ + + /** + * The OTA update not needed since current eUICC OS is latest. + * @hide + */ + @SystemApi public static final int EUICC_OTA_NOT_NEEDED = 4; - /** The OTA status is unavailable since eUICC service is unavailable. */ + + /** + * The OTA status is unavailable since eUICC service is unavailable. + * @hide + */ + @SystemApi public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; private final Context mContext; @@ -276,8 +297,10 @@ public class EuiccManager { * * @return the status of eUICC OTA. If {@link #isEnabled()} is false or the eUICC is not ready, * {@link OtaStatus#EUICC_OTA_STATUS_UNAVAILABLE} will be returned. - * TODO(b/35851809): Make this a SystemApi. + * + * @hide */ + @SystemApi public int getOtaStatus() { if (!isEnabled()) { return EUICC_OTA_STATUS_UNAVAILABLE; @@ -292,7 +315,7 @@ public class EuiccManager { /** * Attempt to download the given {@link DownloadableSubscription}. * - * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, + * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, * or the calling app must be authorized to manage both the currently-active subscription and * the subscription to be downloaded according to the subscription metadata. Without the former, * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback @@ -354,14 +377,16 @@ public class EuiccManager { * * <p>To be called by the LUI upon completion of a resolvable error flow. * + * <p>Requires that the calling app has the + * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. + * * @param resolutionIntent The original intent used to start the LUI. * @param resolutionExtras Resolution-specific extras depending on the result of the resolution. * For example, this may indicate whether the user has consented or may include the input * they provided. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ + @SystemApi public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) { if (!isEnabled()) { PendingIntent callbackIntent = @@ -395,9 +420,8 @@ public class EuiccManager { * @param subscription the subscription which needs metadata filled in * @param callbackIntent a PendingIntent to launch when the operation completes. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ + @SystemApi public void getDownloadableSubscriptionMetadata( DownloadableSubscription subscription, PendingIntent callbackIntent) { if (!isEnabled()) { @@ -426,9 +450,8 @@ public class EuiccManager { * * @param callbackIntent a PendingIntent to launch when the operation completes. * @hide - * - * TODO(b/35851809): Make this a SystemApi. */ + @SystemApi public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) { if (!isEnabled()) { sendUnavailableError(callbackIntent); @@ -468,7 +491,7 @@ public class EuiccManager { * * <p>Requires that the calling app has carrier privileges according to the metadata of the * profile to be deleted, or the - * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. + * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. * * @param subscriptionId the ID of the subscription to delete. * @param callbackIntent a PendingIntent to launch when the operation completes. @@ -489,7 +512,7 @@ public class EuiccManager { /** * Switch to (enable) the given subscription. * - * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, + * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, * or the calling app must be authorized to manage both the currently-active subscription and * the subscription to be enabled according to the subscription metadata. Without the former, * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback @@ -599,11 +622,7 @@ public class EuiccManager { } } - /** - * @hide - */ - @TestApi - protected IEuiccController getIEuiccController() { + private static IEuiccController getIEuiccController() { return IEuiccController.Stub.asInterface(ServiceManager.getService("econtroller")); } } diff --git a/telephony/java/android/telephony/euicc/EuiccNotification.java b/telephony/java/android/telephony/euicc/EuiccNotification.java index ef3c1ce8cf3b..43a770748260 100644 --- a/telephony/java/android/telephony/euicc/EuiccNotification.java +++ b/telephony/java/android/telephony/euicc/EuiccNotification.java @@ -17,6 +17,7 @@ package android.telephony.euicc; import android.annotation.IntDef; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -31,10 +32,9 @@ import java.util.Objects; * disabling, or deleting). * * @hide - * - * TODO(b/35851809): Make this a @SystemApi. */ -public class EuiccNotification implements Parcelable { +@SystemApi +public final class EuiccNotification implements Parcelable { /** Event */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "EVENT_" }, value = { @@ -43,6 +43,7 @@ public class EuiccNotification implements Parcelable { EVENT_DISABLE, EVENT_DELETE }) + /** @hide */ public @interface Event {} /** A profile is downloaded and installed. */ @@ -57,7 +58,7 @@ public class EuiccNotification implements Parcelable { /** A profile is deleted. */ public static final int EVENT_DELETE = 1 << 3; - /** Value of the bits of all above events */ + /** Value of the bits of all the events including install, enable, disable and delete. */ @Event public static final int ALL_EVENTS = EVENT_INSTALL | EVENT_ENABLE | EVENT_DISABLE | EVENT_DELETE; diff --git a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java index 7efe04364280..67ae983efeb0 100644 --- a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java +++ b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java @@ -16,6 +16,7 @@ package android.telephony.euicc; import android.annotation.IntDef; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.service.carrier.CarrierIdentifier; @@ -27,20 +28,21 @@ import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; /** * This represents the RAT (Rules Authorisation Table) stored on eUICC. - * * @hide - * - * TODO(b/35851809): Make this a @SystemApi. */ +@SystemApi public final class EuiccRulesAuthTable implements Parcelable { /** Profile policy rule flags */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "POLICY_RULE_FLAG_" }, value = { POLICY_RULE_FLAG_CONSENT_REQUIRED }) + /** @hide */ public @interface PolicyRuleFlag {} /** User consent is required to install the profile. */ @@ -89,12 +91,14 @@ public final class EuiccRulesAuthTable implements Parcelable { * @throws ArrayIndexOutOfBoundsException If the {@code mPosition} is larger than the size * this table. */ - public Builder add(int policyRules, CarrierIdentifier[] carrierId, int policyRuleFlags) { + public Builder add(int policyRules, List<CarrierIdentifier> carrierId, int policyRuleFlags) { if (mPosition >= mPolicyRules.length) { throw new ArrayIndexOutOfBoundsException(mPosition); } mPolicyRules[mPosition] = policyRules; - mCarrierIds[mPosition] = carrierId; + if (carrierId != null && carrierId.size() > 0) { + mCarrierIds[mPosition] = carrierId.toArray(new CarrierIdentifier[carrierId.size()]); + } mPolicyRuleFlags[mPosition] = policyRuleFlags; mPosition++; return this; diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java index 207965d5a2f6..da322114d993 100644 --- a/telephony/java/android/telephony/ims/ImsCallSession.java +++ b/telephony/java/android/telephony/ims/ImsCallSession.java @@ -753,6 +753,22 @@ public class ImsCallSession { } /** + * Deflects an incoming call. + * + * @param number number to be deflected to + */ + public void deflect(String number) { + if (mClosed) { + return; + } + + try { + miSession.deflect(number); + } catch (RemoteException e) { + } + } + + /** * Rejects an incoming call or session update. * * @param reason reason code to reject an incoming call diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java index 7b7749102590..7d654305015e 100644 --- a/telephony/java/android/telephony/ims/ImsReasonInfo.java +++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java @@ -393,6 +393,12 @@ public final class ImsReasonInfo implements Parcelable { */ public static final int CODE_SIP_ALTERNATE_EMERGENCY_CALL = 1514; + /** + * Call failed because of unobtainable number + * @hide + */ + public static final int CODE_UNOBTAINABLE_NUMBER = 1515; + /* OEM specific error codes. To be used by OEMs when they don't want to reveal error code which would be replaced by ERROR_UNSPECIFIED */ public static final int CODE_OEM_CAUSE_1 = 0xf001; diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java index 00cb1e25f66d..e5ed82572873 100644 --- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java +++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java @@ -182,6 +182,15 @@ public class ImsCallSessionImplBase extends IImsCallSession.Stub { } /** + * Deflects an incoming call. + * + * @param deflectNumber number to deflect the call + */ + @Override + public void deflect(String deflectNumber) { + } + + /** * Rejects an incoming call or session update. * * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}. diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index bfdd4533275b..1fdbae9186b7 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -80,7 +80,7 @@ public abstract class ImsFeature { public static final String EXTRA_PHONE_ID = "android:phone_id"; /** - * Invalid feature value\ + * Invalid feature value * @hide */ public static final int FEATURE_INVALID = -1; diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java index c6ca6fdb0fd8..7b9fe2b144ab 100644 --- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java @@ -174,6 +174,11 @@ public class ImsCallSessionImplBase implements AutoCloseable { } @Override + public void deflect(String deflectNumber) { + ImsCallSessionImplBase.this.deflect(deflectNumber); + } + + @Override public void reject(int reason) { ImsCallSessionImplBase.this.reject(reason); } @@ -395,6 +400,14 @@ public class ImsCallSessionImplBase implements AutoCloseable { } /** + * Deflects an incoming call. + * + * @param deflectNumber number to deflect the call + */ + public void deflect(String deflectNumber) { + } + + /** * Rejects an incoming call or session update. * * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}. diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl index 203e6cf9c577..15234e5c0e92 100644 --- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl +++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl @@ -136,6 +136,13 @@ interface IImsCallSession { void accept(int callType, in ImsStreamMediaProfile profile); /** + * Deflects an incoming call. + * + * @param deflectNumber number to deflect the call + */ + void deflect(String deflectNumber); + + /** * Rejects an incoming call or session update. * * @param reason reason code to reject an incoming call diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 2b4c059cf69f..02cc82cf56b0 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1123,33 +1123,33 @@ interface ITelephony { boolean isHearingAidCompatibilitySupported(); /** - * Get IMS Registration Status - */ - boolean isImsRegistered(); - - /** * Get IMS Registration Status on a particular subid. * * @param subId user preferred subId. * * @return {@code true} if the IMS status is registered. */ - boolean isImsRegisteredForSubscriber(int subId); + boolean isImsRegistered(int subId); /** - * Returns the Status of Wi-Fi Calling + * Returns the Status of Wi-Fi Calling for the subscription id specified. */ - boolean isWifiCallingAvailable(); + boolean isWifiCallingAvailable(int subId); /** - * Returns the Status of Volte + * Returns the Status of VoLTE for the subscription ID specified. */ - boolean isVolteAvailable(); + boolean isVolteAvailable(int subId); /** - * Returns the Status of VT (video telephony) + * Returns the Status of VT (video telephony) for the subscription ID specified. */ - boolean isVideoTelephonyAvailable(); + boolean isVideoTelephonyAvailable(int subId); + + /** + * Returns the MMTEL IMS registration technology for the subsciption ID specified. + */ + int getImsRegTechnologyForMmTel(int subId); /** * Returns the unique device ID of phone, for example, the IMEI for diff --git a/test-base/Android.bp b/test-base/Android.bp index 62fed61da276..49122249ce25 100644 --- a/test-base/Android.bp +++ b/test-base/Android.bp @@ -24,6 +24,13 @@ java_library { srcs: ["src/**/*.java"], + errorprone: { + javacflags: ["-Xep:DepAnn:ERROR"], + }, + + // Needs to be consistent with the repackaged version of this make target. + java_version: "1.8", + no_framework_libs: true, hostdex: true, libs: [ @@ -55,21 +62,22 @@ java_library_static { name: "repackaged.android.test.base", static_libs: ["android.test.base"], - no_framework_libs: true, libs: [ "framework", ], jarjar_rules: "jarjar-rules.txt", + // Pin java_version until jarjar is certified to support later versions. http://b/72703434 + java_version: "1.8", } // Build the android.test.base-minus-junit library // =============================================== // This contains the android.test classes from android.test.base plus // the com.android.internal.util.Predicate[s] classes. This is only -// intended for inclusion in the android.test.legacy static library and -// must not be used elsewhere. +// intended for inclusion in the android.test.legacy and +// legacy-android-test static libraries and must not be used elsewhere. java_library_static { name: "android.test.base-minus-junit", diff --git a/test-base/src/android/test/PerformanceTestCase.java b/test-base/src/android/test/PerformanceTestCase.java index 65bd4a48f7f5..2584da20e9be 100644 --- a/test-base/src/android/test/PerformanceTestCase.java +++ b/test-base/src/android/test/PerformanceTestCase.java @@ -21,6 +21,11 @@ package android.test; * * If you want your test to be used as a performance test, you must * implement this interface. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html"> + * AndroidJUnitRunner</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ @Deprecated public interface PerformanceTestCase diff --git a/test-mock/Android.bp b/test-mock/Android.bp index b1ae40e17b9d..54e07a1673e7 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -19,6 +19,8 @@ java_library { name: "android.test.mock", + // Needs to be consistent with the repackaged version of this make target. + java_version: "1.8", srcs: ["src/**/*.java"], no_framework_libs: true, @@ -35,4 +37,6 @@ java_library_static { static_libs: ["android.test.mock"], jarjar_rules: "jarjar-rules.txt", + // Pin java_version until jarjar is certified to support later versions. http://b/72703434 + java_version: "1.8", } diff --git a/test-mock/api/android-test-mock-current.txt b/test-mock/api/android-test-mock-current.txt index 73f794b8e431..10286c297152 100644 --- a/test-mock/api/android-test-mock-current.txt +++ b/test-mock/api/android-test-mock-current.txt @@ -1,5 +1,9 @@ package android.test.mock { + public deprecated class MockAccountManager { + method public static android.accounts.AccountManager newMockAccountManager(android.content.Context); + } + public deprecated class MockApplication extends android.app.Application { ctor public MockApplication(); } @@ -9,6 +13,7 @@ package android.test.mock { ctor public MockContentProvider(android.content.Context); ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]); method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>); + method public static deprecated void attachInfoForTesting(android.content.ContentProvider, android.content.Context, android.content.pm.ProviderInfo); method public int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public final android.content.IContentProvider getIContentProvider(); method public java.lang.String getType(android.net.Uri); @@ -411,5 +416,9 @@ package android.test.mock { method public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics); } + public deprecated class MockService { + method public static <T extends android.app.Service> void attachForTesting(android.app.Service, android.content.Context, java.lang.String, android.app.Application); + } + } diff --git a/test-mock/src/android/test/mock/MockAccountManager.java b/test-mock/src/android/test/mock/MockAccountManager.java new file mode 100644 index 000000000000..c9b4c7ba0f8f --- /dev/null +++ b/test-mock/src/android/test/mock/MockAccountManager.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.test.mock; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AccountManagerCallback; +import android.accounts.AccountManagerFuture; +import android.accounts.AuthenticatorException; +import android.accounts.OnAccountsUpdateListener; +import android.accounts.OperationCanceledException; +import android.content.Context; +import android.os.Handler; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * A mock {@link android.accounts.AccountManager} class. + * + * <p>Provided for use by {@code android.test.IsolatedContext}. + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot} + * tools/testing-support-library/index.html">Android Testing Support Library</a>. + */ +@Deprecated +public class MockAccountManager { + + /** + * Create a new mock {@link AccountManager} instance. + * + * @param context the {@link Context} to which the returned object belongs. + * @return the new instance. + */ + public static AccountManager newMockAccountManager(Context context) { + return new MockAccountManagerImpl(context); + } + + private MockAccountManager() { + } + + private static class MockAccountManagerImpl extends AccountManager { + + MockAccountManagerImpl(Context context) { + super(context, null /* IAccountManager */, null /* handler */); + } + + public void addOnAccountsUpdatedListener(OnAccountsUpdateListener listener, + Handler handler, boolean updateImmediately) { + // do nothing + } + + public Account[] getAccounts() { + return new Account[] {}; + } + + public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures( + final String type, final String[] features, + AccountManagerCallback<Account[]> callback, Handler handler) { + return new MockAccountManagerFuture<Account[]>(new Account[0]); + } + + public String blockingGetAuthToken(Account account, String authTokenType, + boolean notifyAuthFailure) + throws OperationCanceledException, IOException, AuthenticatorException { + return null; + } + } + + /** + * A very simple AccountManagerFuture class + * that returns what ever was passed in + */ + private static class MockAccountManagerFuture<T> + implements AccountManagerFuture<T> { + + T mResult; + + MockAccountManagerFuture(T result) { + mResult = result; + } + + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + public boolean isCancelled() { + return false; + } + + public boolean isDone() { + return true; + } + + public T getResult() + throws OperationCanceledException, IOException, AuthenticatorException { + return mResult; + } + + public T getResult(long timeout, TimeUnit unit) + throws OperationCanceledException, IOException, AuthenticatorException { + return getResult(); + } + } +} diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java index d5f3ce880b8f..b917fbd8a1fe 100644 --- a/test-mock/src/android/test/mock/MockContentProvider.java +++ b/test-mock/src/android/test/mock/MockContentProvider.java @@ -277,4 +277,21 @@ public class MockContentProvider extends ContentProvider { public final IContentProvider getIContentProvider() { return mIContentProvider; } + + /** + * Like {@link #attachInfo(Context, android.content.pm.ProviderInfo)}, but for use + * when directly instantiating the provider for testing. + * + * <p>Provided for use by {@code android.test.ProviderTestCase2} and + * {@code android.test.RenamingDelegatingContext}. + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. + */ + @Deprecated + public static void attachInfoForTesting( + ContentProvider provider, Context context, ProviderInfo providerInfo) { + provider.attachInfoForTesting(context, providerInfo); + } } diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java index 7e08f51cd87d..da70f0f0c96e 100644 --- a/test-mock/src/android/test/mock/MockPackageManager.java +++ b/test-mock/src/android/test/mock/MockPackageManager.java @@ -47,6 +47,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; +import android.content.pm.dex.ArtManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Rect; @@ -1184,4 +1185,12 @@ public class MockPackageManager extends PackageManager { @Nullable DexModuleRegisterCallback callback) { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + @Override + public ArtManager getArtManager() { + throw new UnsupportedOperationException(); + } } diff --git a/test-mock/src/android/test/mock/MockService.java b/test-mock/src/android/test/mock/MockService.java new file mode 100644 index 000000000000..dbba4f329eae --- /dev/null +++ b/test-mock/src/android/test/mock/MockService.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.test.mock; + +import android.app.Application; +import android.app.Service; +import android.content.Context; + +/** + * A mock {@link android.app.Service} class. + * + * <p>Provided for use by {@code android.test.ServiceTestCase}. + * + * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>. + * New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. + */ +@Deprecated +public class MockService { + + public static <T extends Service> void attachForTesting(Service service, Context context, + String serviceClassName, + Application application) { + service.attach( + context, + null, // ActivityThread not actually used in Service + serviceClassName, + null, // token not needed when not talking with the activity manager + application, + null // mocked services don't talk with the activity manager + ); + } + + private MockService() { + } +} diff --git a/test-runner/Android.bp b/test-runner/Android.bp index dfaeed5e271e..fb7c2a7f651f 100644 --- a/test-runner/Android.bp +++ b/test-runner/Android.bp @@ -19,8 +19,14 @@ java_library { name: "android.test.runner", + // Needs to be consistent with the repackaged version of this make target. + java_version: "1.8", srcs: ["src/**/*.java"], + errorprone: { + javacflags: ["-Xep:DepAnn:ERROR"], + }, + no_framework_libs: true, libs: [ "framework", @@ -31,7 +37,8 @@ java_library { // Build the android.test.runner-minus-junit library // ================================================= -// This is provided solely for use by the legacy-android-test module. +// This is only intended for inclusion in the android.test.legacy and +// legacy-android-test static libraries and must not be used elsewhere. java_library { name: "android.test.runner-minus-junit", @@ -54,4 +61,6 @@ java_library_static { static_libs: ["android.test.runner"], jarjar_rules: "jarjar-rules.txt", + // Pin java_version until jarjar is certified to support later versions. http://b/72703434 + java_version: "1.8", } diff --git a/test-runner/src/android/test/ComparisonFailure.java b/test-runner/src/android/test/ComparisonFailure.java index 3fa76f5b166c..d86b7007a733 100644 --- a/test-runner/src/android/test/ComparisonFailure.java +++ b/test-runner/src/android/test/ComparisonFailure.java @@ -19,8 +19,9 @@ package android.test; /** * Thrown when an assert equals for Strings failed. * - * @deprecated use junit.framework.ComparisonFailure + * @deprecated use org.junit.ComparisonFailure */ +@Deprecated public class ComparisonFailure extends AssertionFailedError { private junit.framework.ComparisonFailure mComparison; diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java index 0b77c0062dfb..6e4c41eef81c 100644 --- a/test-runner/src/android/test/IsolatedContext.java +++ b/test-runner/src/android/test/IsolatedContext.java @@ -17,12 +17,6 @@ package android.test; import android.accounts.AccountManager; -import android.accounts.AccountManagerCallback; -import android.accounts.AccountManagerFuture; -import android.accounts.AuthenticatorException; -import android.accounts.OnAccountsUpdateListener; -import android.accounts.OperationCanceledException; -import android.accounts.Account; import android.content.ContextWrapper; import android.content.ContentResolver; import android.content.Intent; @@ -32,12 +26,10 @@ import android.content.BroadcastReceiver; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.Uri; -import android.os.Handler; +import android.test.mock.MockAccountManager; import java.io.File; -import java.io.IOException; import java.util.ArrayList; -import java.util.concurrent.TimeUnit; import java.util.List; @@ -52,7 +44,7 @@ import java.util.List; public class IsolatedContext extends ContextWrapper { private ContentResolver mResolver; - private final MockAccountManager mMockAccountManager; + private final AccountManager mMockAccountManager; private List<Intent> mBroadcastIntents = new ArrayList<>(); @@ -60,7 +52,7 @@ public class IsolatedContext extends ContextWrapper { ContentResolver resolver, Context targetContext) { super(targetContext); mResolver = resolver; - mMockAccountManager = new MockAccountManager(); + mMockAccountManager = MockAccountManager.newMockAccountManager(IsolatedContext.this); } /** Returns the list of intents that were broadcast since the last call to this method. */ @@ -123,71 +115,6 @@ public class IsolatedContext extends ContextWrapper { return null; } - private class MockAccountManager extends AccountManager { - public MockAccountManager() { - super(IsolatedContext.this, null /* IAccountManager */, null /* handler */); - } - - public void addOnAccountsUpdatedListener(OnAccountsUpdateListener listener, - Handler handler, boolean updateImmediately) { - // do nothing - } - - public Account[] getAccounts() { - return new Account[]{}; - } - - public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures( - final String type, final String[] features, - AccountManagerCallback<Account[]> callback, Handler handler) { - return new MockAccountManagerFuture<Account[]>(new Account[0]); - } - - public String blockingGetAuthToken(Account account, String authTokenType, - boolean notifyAuthFailure) - throws OperationCanceledException, IOException, AuthenticatorException { - return null; - } - - - /** - * A very simple AccountManagerFuture class - * that returns what ever was passed in - */ - private class MockAccountManagerFuture<T> - implements AccountManagerFuture<T> { - - T mResult; - - public MockAccountManagerFuture(T result) { - mResult = result; - } - - public boolean cancel(boolean mayInterruptIfRunning) { - return false; - } - - public boolean isCancelled() { - return false; - } - - public boolean isDone() { - return true; - } - - public T getResult() - throws OperationCanceledException, IOException, AuthenticatorException { - return mResult; - } - - public T getResult(long timeout, TimeUnit unit) - throws OperationCanceledException, IOException, AuthenticatorException { - return getResult(); - } - } - - } - @Override public File getFilesDir() { return new File("/dev/null"); diff --git a/test-runner/src/android/test/ProviderTestCase2.java b/test-runner/src/android/test/ProviderTestCase2.java index 1fa633e26961..be18b53059f3 100644 --- a/test-runner/src/android/test/ProviderTestCase2.java +++ b/test-runner/src/android/test/ProviderTestCase2.java @@ -21,6 +21,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.pm.ProviderInfo; import android.content.res.Resources; +import android.test.mock.MockContentProvider; import android.test.mock.MockContext; import android.test.mock.MockContentResolver; import android.database.DatabaseUtils; @@ -152,7 +153,7 @@ public abstract class ProviderTestCase2<T extends ContentProvider> extends Andro T instance = providerClass.newInstance(); ProviderInfo providerInfo = new ProviderInfo(); providerInfo.authority = authority; - instance.attachInfoForTesting(context, providerInfo); + MockContentProvider.attachInfoForTesting(instance, context, providerInfo); return instance; } diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java index fd3332154611..10ccebc42dd0 100644 --- a/test-runner/src/android/test/RenamingDelegatingContext.java +++ b/test-runner/src/android/test/RenamingDelegatingContext.java @@ -21,6 +21,7 @@ import android.content.ContextWrapper; import android.content.ContentProvider; import android.database.DatabaseErrorHandler; import android.database.sqlite.SQLiteDatabase; +import android.test.mock.MockContentProvider; import android.util.Log; import java.io.File; @@ -71,7 +72,7 @@ public class RenamingDelegatingContext extends ContextWrapper { if (allowAccessToExistingFilesAndDbs) { mContext.makeExistingFilesAndDbsAccessible(); } - mProvider.attachInfoForTesting(mContext, null); + MockContentProvider.attachInfoForTesting(mProvider, mContext, null); return mProvider; } diff --git a/test-runner/src/android/test/ServiceTestCase.java b/test-runner/src/android/test/ServiceTestCase.java index c8ff0f904d6d..cd54955f22fa 100644 --- a/test-runner/src/android/test/ServiceTestCase.java +++ b/test-runner/src/android/test/ServiceTestCase.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.os.IBinder; import android.test.mock.MockApplication; +import android.test.mock.MockService; import java.util.Random; /** @@ -163,14 +164,8 @@ public abstract class ServiceTestCase<T extends Service> extends AndroidTestCase if (getApplication() == null) { setApplication(new MockApplication()); } - mService.attach( - getContext(), - null, // ActivityThread not actually used in Service - mServiceClass.getName(), - null, // token not needed when not talking with the activity manager - getApplication(), - null // mocked services don't talk with the activity manager - ); + MockService.attachForTesting( + mService, getContext(), mServiceClass.getName(), getApplication()); assertNotNull(mService); diff --git a/test-runner/src/android/test/TestSuiteProvider.java b/test-runner/src/android/test/TestSuiteProvider.java index c74651cea01f..12cfcb76e10b 100644 --- a/test-runner/src/android/test/TestSuiteProvider.java +++ b/test-runner/src/android/test/TestSuiteProvider.java @@ -20,6 +20,11 @@ import junit.framework.TestSuite; /** * Implementors will know how to get a test suite. + * + * @deprecated Use + * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html"> + * AndroidJUnitRunner</a> instead. New tests should be written using the + * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. */ @Deprecated public interface TestSuiteProvider { diff --git a/test-runner/src/junit/runner/BaseTestRunner.java b/test-runner/src/junit/runner/BaseTestRunner.java index e7e043133c95..b2fa16c91da2 100644 --- a/test-runner/src/junit/runner/BaseTestRunner.java +++ b/test-runner/src/junit/runner/BaseTestRunner.java @@ -207,6 +207,7 @@ public abstract class BaseTestRunner implements TestListener { * * @deprecated not present in JUnit4.10 */ + @Deprecated public TestSuiteLoader getLoader() { return new StandardTestSuiteLoader(); } @@ -279,6 +280,7 @@ public abstract class BaseTestRunner implements TestListener { // BEGIN android-changed - add back this method for API compatibility /** @deprecated not present in JUnit4.10 */ + @Deprecated public static boolean inVAJava() { return false; } diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java index cc792cc749d9..03a617c354fa 100644 --- a/tests/net/java/android/net/ConnectivityManagerTest.java +++ b/tests/net/java/android/net/ConnectivityManagerTest.java @@ -38,6 +38,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; @@ -217,7 +218,8 @@ public class ConnectivityManagerTest { // callback triggers captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE)); - verify(callback, timeout(500).times(1)).onAvailable(any()); + verify(callback, timeout(500).times(1)).onAvailable(any(Network.class), + any(NetworkCapabilities.class), any(LinkProperties.class)); // unregister callback manager.unregisterNetworkCallback(callback); @@ -244,7 +246,8 @@ public class ConnectivityManagerTest { // callback triggers captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE)); - verify(callback, timeout(100).times(1)).onAvailable(any()); + verify(callback, timeout(100).times(1)).onAvailable(any(Network.class), + any(NetworkCapabilities.class), any(LinkProperties.class)); // unregister callback manager.unregisterNetworkCallback(callback); @@ -335,6 +338,10 @@ public class ConnectivityManagerTest { static Message makeMessage(NetworkRequest req, int messageType) { Bundle bundle = new Bundle(); bundle.putParcelable(NetworkRequest.class.getSimpleName(), req); + // Pass default objects as we don't care which get passed here + bundle.putParcelable(Network.class.getSimpleName(), new Network(1)); + bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities()); + bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties()); Message msg = Message.obtain(); msg.what = messageType; msg.setData(bundle); diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java index f6c5532363e8..f186ee55d2c7 100644 --- a/tests/net/java/android/net/IpSecConfigTest.java +++ b/tests/net/java/android/net/IpSecConfigTest.java @@ -17,6 +17,7 @@ package android.net; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -48,18 +49,12 @@ public class IpSecConfigTest { assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId()); } - @Test - public void testParcelUnparcel() throws Exception { - assertParcelingIsLossless(new IpSecConfig()); - + private IpSecConfig getSampleConfig() { IpSecConfig c = new IpSecConfig(); c.setMode(IpSecTransform.MODE_TUNNEL); c.setSourceAddress("0.0.0.0"); c.setDestinationAddress("1.2.3.4"); - c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP); - c.setEncapSocketResourceId(7); - c.setEncapRemotePort(22); - c.setNattKeepaliveInterval(42); + c.setSpiResourceId(1984); c.setEncryption( new IpSecAlgorithm( IpSecAlgorithm.CRYPT_AES_CBC, @@ -68,7 +63,37 @@ public class IpSecConfigTest { new IpSecAlgorithm( IpSecAlgorithm.AUTH_HMAC_MD5, new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0})); - c.setSpiResourceId(1984); + c.setAuthenticatedEncryption( + new IpSecAlgorithm( + IpSecAlgorithm.AUTH_CRYPT_AES_GCM, + new byte[] { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0, 1, 2, 3, 4 + }, + 128)); + c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP); + c.setEncapSocketResourceId(7); + c.setEncapRemotePort(22); + c.setNattKeepaliveInterval(42); + c.setMarkValue(12); + c.setMarkMask(23); + + return c; + } + + @Test + public void testCopyConstructor() { + IpSecConfig original = getSampleConfig(); + IpSecConfig copy = new IpSecConfig(original); + + assertTrue(IpSecConfig.equals(original, copy)); + assertFalse(original == copy); + } + + @Test + public void testParcelUnparcel() throws Exception { + assertParcelingIsLossless(new IpSecConfig()); + + IpSecConfig c = getSampleConfig(); assertParcelingIsLossless(c); } diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/tests/net/java/android/net/IpSecTransformTest.java new file mode 100644 index 000000000000..ffd1f063e48b --- /dev/null +++ b/tests/net/java/android/net/IpSecTransformTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.support.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link IpSecTransform}. */ +@SmallTest +@RunWith(JUnit4.class) +public class IpSecTransformTest { + + @Test + public void testCreateTransformCopiesConfig() { + // Create a config with a few parameters to make sure it's not empty + IpSecConfig config = new IpSecConfig(); + config.setSourceAddress("0.0.0.0"); + config.setDestinationAddress("1.2.3.4"); + config.setSpiResourceId(1984); + + IpSecTransform preModification = new IpSecTransform(null, config); + + config.setSpiResourceId(1985); + IpSecTransform postModification = new IpSecTransform(null, config); + + assertFalse(IpSecTransform.equals(preModification, postModification)); + } + + @Test + public void testCreateTransformsWithSameConfigEqual() { + // Create a config with a few parameters to make sure it's not empty + IpSecConfig config = new IpSecConfig(); + config.setSourceAddress("0.0.0.0"); + config.setDestinationAddress("1.2.3.4"); + config.setSpiResourceId(1984); + + IpSecTransform config1 = new IpSecTransform(null, config); + IpSecTransform config2 = new IpSecTransform(null, config); + + assertTrue(IpSecTransform.equals(config1, config2)); + } +} diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java index 9aad413c354b..04266c5b3a0f 100644 --- a/tests/net/java/android/net/MacAddressTest.java +++ b/tests/net/java/android/net/MacAddressTest.java @@ -172,7 +172,7 @@ public class MacAddressTest { final int iterations = 1000; final String expectedAndroidOui = "da:a1:19"; for (int i = 0; i < iterations; i++) { - MacAddress mac = MacAddress.createRandomUnicastAddress(); + MacAddress mac = MacAddress.createRandomUnicastAddressWithGoogleBase(); String stringRepr = mac.toString(); assertTrue(stringRepr + " expected to be a locally assigned address", @@ -195,6 +195,15 @@ public class MacAddressTest { assertTrue(stringRepr + " expected to begin with " + expectedLocalOui, stringRepr.startsWith(expectedLocalOui)); } + + for (int i = 0; i < iterations; i++) { + MacAddress mac = MacAddress.createRandomUnicastAddress(); + String stringRepr = mac.toString(); + + assertTrue(stringRepr + " expected to be a locally assigned address", + mac.isLocallyAssigned()); + assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType()); + } } @Test diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index e7abede4cda4..28f81220027c 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -35,6 +35,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; @@ -49,6 +50,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; import static com.android.internal.util.TestUtils.waitForIdleHandler; +import static com.android.internal.util.TestUtils.waitForIdleLooper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -84,6 +86,7 @@ import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager.PacketKeepalive; import android.net.ConnectivityManager.PacketKeepaliveCallback; import android.net.ConnectivityManager.TooManyRequestsException; +import android.net.ConnectivityThread; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.IpPrefix; @@ -278,6 +281,7 @@ public class ConnectivityServiceTest { waitForIdle(mWiFiNetworkAgent, timeoutMs); waitForIdle(mEthernetNetworkAgent, timeoutMs); waitForIdleHandler(mService.mHandlerThread, timeoutMs); + waitForIdleLooper(ConnectivityThread.getInstanceLooper(), timeoutMs); } public void waitForIdle(MockNetworkAgent agent, long timeoutMs) { @@ -528,6 +532,11 @@ public class ConnectivityServiceTest { mNetworkAgent.sendNetworkInfo(mNetworkInfo); } + public void resume() { + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } + public void disconnect() { mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); mNetworkAgent.sendNetworkInfo(mNetworkInfo); @@ -569,6 +578,10 @@ public class ConnectivityServiceTest { assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS)); return mRedirectUrl; } + + public NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } } /** @@ -1273,6 +1286,7 @@ public class ConnectivityServiceTest { NETWORK_CAPABILITIES, LINK_PROPERTIES, SUSPENDED, + RESUMED, LOSING, LOST, UNAVAILABLE @@ -1344,6 +1358,11 @@ public class ConnectivityServiceTest { } @Override + public void onNetworkResumed(Network network) { + setLastCallback(CallbackState.RESUMED, network, null); + } + + @Override public void onLosing(Network network, int maxMsToLive) { setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */); } @@ -1422,9 +1441,9 @@ public class ConnectivityServiceTest { expectCallback(CallbackState.SUSPENDED, agent, timeoutMs); } if (expectValidated) { - expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent); + expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent, timeoutMs); } else { - expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent); + expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent, timeoutMs); } expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs); } @@ -1463,14 +1482,24 @@ public class ConnectivityServiceTest { } NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent) { - CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent); + return expectCapabilitiesWith(capability, agent, TIMEOUT_MS); + } + + NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent, + int timeoutMs) { + CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs); NetworkCapabilities nc = (NetworkCapabilities) cbi.arg; assertTrue(nc.hasCapability(capability)); return nc; } NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent) { - CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent); + return expectCapabilitiesWithout(capability, agent, TIMEOUT_MS); + } + + NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent, + int timeoutMs) { + CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs); NetworkCapabilities nc = (NetworkCapabilities) cbi.arg; assertFalse(nc.hasCapability(capability)); return nc; @@ -1815,6 +1844,51 @@ public class ConnectivityServiceTest { } @Test + public void testNetworkGoesIntoBackgroundAfterLinger() { + setMobileDataAlwaysOn(true); + NetworkRequest request = new NetworkRequest.Builder() + .clearCapabilities() + .build(); + TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(request, callback); + + TestNetworkCallback defaultCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultCallback); + + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + + mCellNetworkAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + + // Wifi comes up and cell lingers. + mWiFiNetworkAgent.connect(true); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); + callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + + // File a request for cellular, then release it. + NetworkRequest cellRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR).build(); + NetworkCallback noopCallback = new NetworkCallback(); + mCm.requestNetwork(cellRequest, noopCallback); + mCm.unregisterNetworkCallback(noopCallback); + callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); + + // Let linger run its course. + callback.assertNoCallback(); + final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4; + callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent, + lingerTimeoutMs); + + // Clean up. + mCm.unregisterNetworkCallback(defaultCallback); + mCm.unregisterNetworkCallback(callback); + } + + @Test public void testExplicitlySelected() { NetworkRequest request = new NetworkRequest.Builder() .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET) @@ -2459,16 +2533,31 @@ public class ConnectivityServiceTest { // Suspend the network. mCellNetworkAgent.suspend(); + cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED, + mCellNetworkAgent); cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); // Register a garden variety default network request. - final TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback(); + TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(dfltNetworkCallback); // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(), // as well as onNetworkSuspended() in rapid succession. dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent, true); dfltNetworkCallback.assertNoCallback(); + mCm.unregisterNetworkCallback(dfltNetworkCallback); + + mCellNetworkAgent.resume(); + cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED, + mCellNetworkAgent); + cellNetworkCallback.expectCallback(CallbackState.RESUMED, mCellNetworkAgent); + cellNetworkCallback.assertNoCallback(); + + dfltNetworkCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(dfltNetworkCallback); + // This time onNetworkSuspended should not be called. + dfltNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + dfltNetworkCallback.assertNoCallback(); mCm.unregisterNetworkCallback(dfltNetworkCallback); mCm.unregisterNetworkCallback(cellNetworkCallback); @@ -3094,6 +3183,9 @@ public class ConnectivityServiceTest { InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8"); InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888"); + final int validKaInterval = 15; + final int invalidKaInterval = 9; + LinkProperties lp = new LinkProperties(); lp.setInterfaceName("wlan12"); lp.addLinkAddress(new LinkAddress(myIPv6, 64)); @@ -3108,36 +3200,37 @@ public class ConnectivityServiceTest { PacketKeepalive ka; // Attempt to start keepalives with invalid parameters and check for errors. - ka = mCm.startNattKeepalive(notMyNet, 25, callback, myIPv4, 1234, dstIPv4); + ka = mCm.startNattKeepalive(notMyNet, validKaInterval, callback, myIPv4, 1234, dstIPv4); callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK); - ka = mCm.startNattKeepalive(myNet, 19, callback, notMyIPv4, 1234, dstIPv4); + ka = mCm.startNattKeepalive(myNet, invalidKaInterval, callback, myIPv4, 1234, dstIPv4); callback.expectError(PacketKeepalive.ERROR_INVALID_INTERVAL); - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 1234, dstIPv6); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 1234, dstIPv6); callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS); - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv6, 1234, dstIPv4); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv4); callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS); - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv6, 1234, dstIPv6); - callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS); // NAT-T is IPv4-only. + // NAT-T is only supported for IPv4. + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv6); + callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS); - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 123456, dstIPv4); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4); callback.expectError(PacketKeepalive.ERROR_INVALID_PORT); - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 123456, dstIPv4); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4); callback.expectError(PacketKeepalive.ERROR_INVALID_PORT); - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED); - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED); // Check that a started keepalive can be stopped. mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS); - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectStarted(); mWiFiNetworkAgent.setStopKeepaliveError(PacketKeepalive.SUCCESS); ka.stop(); @@ -3145,7 +3238,7 @@ public class ConnectivityServiceTest { // Check that deleting the IP address stops the keepalive. LinkProperties bogusLp = new LinkProperties(lp); - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectStarted(); bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25)); bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25)); @@ -3154,7 +3247,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.sendLinkProperties(lp); // Check that a started keepalive is stopped correctly when the network disconnects. - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectStarted(); mWiFiNetworkAgent.disconnect(); waitFor(mWiFiNetworkAgent.getDisconnectedCV()); @@ -3171,7 +3264,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS); // Check things work as expected when the keepalive is stopped and the network disconnects. - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectStarted(); ka.stop(); mWiFiNetworkAgent.disconnect(); @@ -3185,13 +3278,14 @@ public class ConnectivityServiceTest { // Check that keepalive slots start from 1 and increment. The first one gets slot 1. mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); - ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4); + ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4); callback.expectStarted(); // The second one gets slot 2. mWiFiNetworkAgent.setExpectedKeepaliveSlot(2); TestKeepaliveCallback callback2 = new TestKeepaliveCallback(); - PacketKeepalive ka2 = mCm.startNattKeepalive(myNet, 25, callback2, myIPv4, 6789, dstIPv4); + PacketKeepalive ka2 = mCm.startNattKeepalive( + myNet, validKaInterval, callback2, myIPv4, 6789, dstIPv4); callback2.expectStarted(); // Now stop the first one and create a third. This also gets slot 1. @@ -3200,7 +3294,8 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); TestKeepaliveCallback callback3 = new TestKeepaliveCallback(); - PacketKeepalive ka3 = mCm.startNattKeepalive(myNet, 25, callback3, myIPv4, 9876, dstIPv4); + PacketKeepalive ka3 = mCm.startNattKeepalive( + myNet, validKaInterval, callback3, myIPv4, 9876, dstIPv4); callback3.expectStarted(); ka2.stop(); @@ -3682,8 +3777,7 @@ public class ConnectivityServiceTest { vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent); - vpnNetworkCallback.expectCapabilitiesLike( - nc -> nc.appliesToUid(uid) && !nc.appliesToUid(uid + 1), vpnNetworkAgent); + vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent); ranges.clear(); vpnNetworkAgent.setUids(ranges); diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt index f278aec8eb6f..d75aea507980 100644 --- a/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt +++ b/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt @@ -1,3 +1,19 @@ +/* + * 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.sdkparcelables import org.objectweb.asm.ClassVisitor @@ -25,4 +41,4 @@ class AncestorCollector(api: Int, dest: ClassVisitor?) : ClassVisitor(api, dest) super.visit(version, access, name, signature, superName, interfaces) } -}
\ No newline at end of file +} diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt index 3e9d92cd978f..22e8d781335b 100644 --- a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt +++ b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt @@ -1,3 +1,19 @@ +/* + * 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.sdkparcelables import org.objectweb.asm.ClassReader @@ -53,4 +69,4 @@ fun main(args: Array<String>) { fun usage() { System.err.println("Usage: <input jar> <output aidl>") kotlin.system.exitProcess(1) -}
\ No newline at end of file +} diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt index 620f798daf48..45027b51d3ef 100644 --- a/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt +++ b/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt @@ -1,3 +1,19 @@ +/* + * 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.sdkparcelables /** A class that uses an ancestor map to find all classes that @@ -11,6 +27,8 @@ class ParcelableDetector { impl.build() return impl.parcelables } + + const val PARCELABLE_CLASS = "android/os/Parcelable" } private class Impl(val ancestors: Map<String, Ancestors>) { @@ -19,7 +37,7 @@ class ParcelableDetector { fun build() { val classList = ancestors.keys - classList.filterTo(parcelables, this::isParcelable) + classList.filterTo(parcelables, { (it != PARCELABLE_CLASS) && isParcelable(it) }) parcelables.sort() } @@ -28,7 +46,7 @@ class ParcelableDetector { return false } - if (c == "android/os/Parcelable") { + if (c == PARCELABLE_CLASS) { return true } diff --git a/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt b/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt index edfc8259a738..f08173d5b2f1 100644 --- a/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt +++ b/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt @@ -1,3 +1,19 @@ +/* + * 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.sdkparcelables import junit.framework.TestCase.assertEquals @@ -12,7 +28,7 @@ class ParcelableDetectorTest { val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap) - assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable")) + assertEquals(parcelables, listOf("android/test/Parcelable")) } @Test @@ -23,7 +39,7 @@ class ParcelableDetectorTest { val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap) - assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable")) + assertEquals(parcelables, listOf("android/test/Parcelable")) } @Test @@ -35,7 +51,7 @@ class ParcelableDetectorTest { val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap) - assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable", "android/test/SuperParcelable")) + assertEquals(parcelables, listOf("android/test/Parcelable", "android/test/SuperParcelable")) } @Test @@ -47,7 +63,7 @@ class ParcelableDetectorTest { val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap) - assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/IParcelable", "android/test/Parcelable")) + assertEquals(parcelables, listOf("android/test/IParcelable", "android/test/Parcelable")) } } |